A. 洛希极限
考场上想的还是太少了.
发现每个点被转移,最优肯定是从自己斜下方转移.
很直接的想法就是线段树,发现每个点只会取最优的,于是可以做一个单调队列.
A_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
#define ll int
#define ull unsigned ll
#define lf long double
#define lbt(x) (x&(-x))
#define mp(x,y) make_pair(x,y)
#define lb lower_bound
#define ub upper_bound
#define Fill(x,y) memset(x,y,sizeof x)
#define Copy(x,y) memcpy(x,y,sizeof x)
#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
inline ll read() {
ll w=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
return cit?w:-w;
}
} using namespace BSS;
const ll N=3e3+21,Q=5e5+21,mod=1e9+7;
ll m,n,ops;
ll bin[Q];
ll le[N][N],ri[N][N],dn[N][N],up[N][N];
struct I { ll r1,c1,r2,c2; } ma[Q],mat[Q];
struct II {
ll len,w;
friend bool operator <(II i,II j){
return i.len<j.len;
}
friend II operator +(II i,II j){
if(j.len>i.len) return j;
return i.w=(i.w+(i.len==j.len)*j.w)%mod,i;
}
} f[N][N];
auto comp=[](I i,I j)->bool{
if(i.r1!=j.r1) return i.r1<j.r1;
if(i.r2!=j.r2) return i.r2<j.r2;
if(i.c1!=j.c1) return i.c1<j.c1;
return i.c2<j.c2;
};
ll getri(ll x,ll y){ return ri[x][y]==0 ? x : ri[x][y]=getri(ri[x][y],y); }
ll getup(ll x,ll y){ return up[x][y]==0 ? y : up[x][y]=getup(x,up[x][y]); }
struct Dull_queue{
ll head,tail; ll cnt[N],pos[N]; II que[N];
inline void clr(){
head=1,tail=0; ll lmt=min(n,m);
for(ll i=0;i<=lmt;i++) cnt[i]=0,pos[i]=0;
}
inline void push(ll x,II y){
while(head<=tail and que[tail]<y)
cnt[que[tail].len]=(cnt[que[tail].len]-que[tail].w+mod)%mod,tail--;
que[++tail]=y,pos[tail]=x,cnt[y.len]=(cnt[y.len]+y.w)%mod;
}
inline II query(ll x){
while(head<=tail and pos[head]<x)
cnt[que[head].len]=(cnt[que[head].len]-que[head].w+mod)%mod,head++;
// cout<<que[head].len<<' '<<cnt[que[head].len]<<" piu\n";
return (II){que[head].len+1,cnt[que[head].len]};
}
}qs[N],qh[N];
auto Work=[]()->void{
n=read(),m=read(),ops=read();
for(ll i=0;i<=n;i++) bin[i]=0;
for(ll i=1;i<=ops;i++){
ma[i].r1=read(),ma[i].c1=read(),ma[i].r2=read(),ma[i].c2=read();
bin[ma[i].r1]++;
}
for(ll i=1;i<=n;i++) bin[i]+=bin[i-1];
for(ll i=1;i<=ops;i++) mat[bin[ma[i].r1]--]=ma[i];
for(ll i=1;i<=ops;i++){
for(ll y=mat[i].c1+1;y<=mat[i].c2;y++)
for(ll x=mat[i].r1+1;x<=mat[i].r2;)
ri[x][y] ? x=getri(x,y) : (le[x][y]=mat[i].r1,ri[x][y]=x+1,x++) ;
}
for(ll i=0;i<=m;i++) bin[i]=0;
for(ll i=1;i<=ops;i++) bin[ma[i].c1]++;
for(ll i=1;i<=m;i++) bin[i]+=bin[i-1];
for(ll i=1;i<=ops;i++) mat[bin[ma[i].c1]--]=ma[i];
for(ll i=1;i<=ops;i++){
for(ll x=mat[i].r1+1;x<=mat[i].r2;x++)
for(ll y=mat[i].c1+1;y<=mat[i].c2;)
up[x][y] ? y=getup(x,y) : (dn[x][y]=mat[i].c1,up[x][y]=y+1,y++) ;
}
for(ll i=1;i<=n;i++){
for(ll j=1;j<=m;j++) f[i][j]=(II){1,1};
}
for(ll i=1;i<=n;i++) qs[i].clr();
for(ll i=1;i<=m;i++) qh[i].clr();
for(ll i=1;i<=n;i++){
for(ll j=1;j<=m;j++){
qs[i].push(j,f[i][j]),qh[j].push(i,f[i][j]);
if(i<n and j<m and dn[i+1][j+1]){
// cout<<f[i][j].len<<' '<<f[i][j].w<<' '<<f[i+1][j+1].len<<' '<<f[i+1][j+1].w<<endl;
f[i+1][j+1]=f[i+1][j+1]+qs[i].query(dn[i+1][j+1]);
// cout<<f[i][j].len<<' '<<f[i][j].w<<' '<<f[i+1][j+1].len<<' '<<f[i+1][j+1].w<<" skr\n";
f[i+1][j+1]=f[i+1][j+1]+qh[j].query(le[i+1][j+1]);
// cout<<f[i][j].len<<' '<<f[i][j].w<<' '<<f[i+1][j+1].len<<' '<<f[i+1][j+1].w<<" der\n";
f[i+1][j+1].w=(f[i+1][j+1].w-f[i][j].w*(f[i][j].len+1==f[i+1][j+1].len)+mod)%mod;
}
}
}
// for(signed long long int i=1;i<=n;i++){
// for(int j=1;j<=m;j++){
// cout<<f[i][j].len<<' '<<f[i][j].w<<endl;
// }
// puts("");
// }
II ans=(II){0,0};
for(ll i=1;i<=n;i++){
for(ll j=1;j<=m;j++){
ans=ans+f[i][j];
le[i][j]=0,ri[i][j]=0,up[i][j]=0,dn[i][j]=0;
}
}
printf("%d %d\n",ans.len,ans.w);
};
signed main(){
File(roche);
for(int Ts=read();Ts;Ts--) Work();
exit(0);
}
B. 特立独行的图
构造题,目前只写了判是否有解,差分约束还没打完.
C. 玩游戏
求导不会,鸽了.
D. 骆驼
打表发现,在任意一个 \(5∗5\) 的棋盘内,从任意一个点出发,都可以到达把棋盘走完后到达棋盘上的另外一个点.
关于更有说服力的证明,可以选择把可以互相到达的点之间连一条边,发现可以构成欧拉路.
发现数据范围,\(N\) 都是 \(5\) 的倍数,于是一个很自然的想法就应该是选择把大棋盘拆成小棋盘.
于是构造就很容易了,灵活使用 \((3,3)\) 的位置,代码会比较好写.
D_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
#define ll int
#define ull unsigned ll
#define lf long double
#define lbt(x) (x&(-x))
#define mp(x,y) make_pair(x,y)
#define lb lower_bound
#define ub upper_bound
#define Fill(x,y) memset(x,y,sizeof x)
#define Copy(x,y) memcpy(x,y,sizeof x)
#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
inline ll read() {
ll w=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
return cit?w:-w;
}
} using namespace BSS;
const ll val[8][6][6]={
{ {0,0,0,0,0,0},{0,0,0,0,0,0},{0,0,0,0,0,0},{0,0,0,0,0,0},{0,0,0,0,0,0},{0,0,0,0,0,0} },
{ {0,0,0,0,0,0},{0,1,19,7,4,20},{0,14,11,22,17,12},{0,8,5,0,9,6},{0,2,18,13,3,21},{0,15,10,23,16,0} },
{ {0,0,0,0,0,0},{0,2,8,24,17,9},{0,13,19,4,12,22},{0,6,16,1,7,25},{0,3,11,23,18,10},{0,14,20,5,15,21} },
{ {0,0,0,0,0,0},{0,2,15,24,8,16},{0,22,10,4,19,11},{0,25,7,1,14,6},{0,3,18,23,9,17},{0,21,13,5,20,12} },
{ {0,0,0,0,0,0},{0,2,7,14,22,6},{0,12,20,4,9,19},{0,15,23,1,16,24},{0,3,8,13,21,5},{0,11,17,25,10,18} },
{ {0,0,0,0,0,0},{0,2,8,25,22,9},{0,15,20,4,12,17},{0,6,23,1,7,24},{0,3,11,16,21,10},{0,14,19,5,13,18} },
{ {0,0,0,0,0,0},{0,2,15,8,5,16},{0,10,25,18,13,24},{0,20,6,1,21,7},{0,3,14,9,4,17},{0,11,22,19,12,23} },
{ {0,0,0,0,0,0},{0,1,6,13,21,5},{0,11,19,3,8,18},{0,14,22,0,15,23},{0,2,7,12,20,4},{0,10,16,24,9,17} }
};
const ll N=1e3+21;
ll m,n,sum;
ll ans[N][N];
auto update=[](ll x,ll y,ll id)->void{
ll valx=5*(x-1),valy=5*(y-1);
for(ll i=1;i<=5;i++){
for(ll j=1;j<=5;j++)
ans[valx+i][valy+j]=val[id][i][j]+sum;
}
};
auto Work1=[]()->void{
update(1,1,1),sum+=23;
for(ll i=2;i<m;i++) update(i,1,4),sum+=25;
update(m,1,2),sum+=25;
for(ll i=m;i>=3;i--){
if(i&1){
for(ll j=2;j<m;j++) update(i,j,2),sum+=25;
update(i,m,5),sum+=25;
}
else{
for(int j=m;j>=3;j--) update(i,j,3),sum+=25;
(i^1) ? (update(i,2,5),sum+=25) : (update(i,2,3),sum+=25) ;
}
}
for(ll i=m;i>=3;i--){
if(i&1) update(2,i,5),sum+=25,update(1,i,3),sum+=25;
else update(1,i,4),sum+=25,update(2,i,3),sum+=25;
}
update(1,2,4),sum+=25,update(2,2,6),ans[5][5]=n*n-1,ans[3][3]=n*n;
};
auto Work2=[]()->void{
update(1,1,7),sum+=24;
for(ll i=2;i<m;i++) update(i,1,4),sum+=25;
update(m,1,2),sum+=25;
for(ll i=m;i>=1;i--){
if(i&1){
for(ll j=m;j>=3;j--) update(i,j,3),sum+=25;
(i^1) ? (update(i,2,5),sum+=25) : (update(i,2,3),sum+=25) ;
}
else{
for(ll j=2;j<m;j++) update(i,j,2),sum+=25;
update(i,m,5),sum+=25;
}
}
ans[3][3]=n*n;
};
signed main(){
File(camel);
n=read(),m=n/5;
if(n==5) puts("1 9 17 2 10"),puts("15 23 6 14 22"),puts("18 3 11 19 4"),puts("25 8 16 24 7"),puts("12 20 5 13 21"),exit(0);
(n&1) ? Work1() : Work2() ;
for(ll i=1;i<=n;i++){
for(ll j=1;j<=n;j++)
printf("%d ",ans[i][j]);
puts("");
}
}