【学习笔记】[POI2015] CZA

最近是真的什么题都做不出来啊

感觉正解藏的稍微深一点就看不出来了

考虑按 1 ∼ n 1\sim n 1n的顺序插入序列。将答案除以 n n n即可。

那么我们唯一要干的事情就是把哪些位置是 固定的 给找出来。

首先,如果一个数小于等于 i − 4 i-4 i4,那么它的旁边都不能插数,可以看作是固定的。并且对于小于等于 i − 4 i-4 i4的数,因为在后续填数的过程中不会影响其左右两边的数,因此在当前状态下一定是合法的。换言之,当填入 i i i过后,我们只需要检验 i − 3 i-3 i3是否合法即可。故而,我们只需要关注 i − 3 , i − 2 , i − 1 i-3,i-2,i-1 i3,i2,i1的相对位置关系,以及是否相邻。这显然可以用最暴力的状压解决,然后就做完了。这玩意用顺逆时针来记录会更简单一些,剩下的全部是手动分讨。

我承认,这个做法非常垃圾。这也导致了代码非常难打。

#include<bits/stdc++.h> #define ll long long #define fi first #define se second #define pb push_back #define inf 0x3f3f3f3f using namespace std; const int N=1e6+5; const int mod=1e9+7; int n,K,D,p[3],ban[N][10],now[2][8],nxt[2][8],res,state[N]; vector<int>vec; void add(int &x,int y){x=(x+y)%mod;} int check(){ vec.clear(); for(int i=1;i<=n;i++){ if(!state[i]){ vec.pb(i); } } for(int i=n;i>=1;i--){ if(state[i]){ vec.pb(i); } } for(int i=0;i+1<vec.size();i++){ if(ban[vec[i]][vec[i+1]-vec[i]+3])return 0; } if(ban[vec.back()][vec[0]-vec.back()+3])return 0; return 1; } int check(int x,int y){ return ban[x][y-x+3]; } void solve1(int x,int s){ int sig=s>>1&1; if((s&1)&&(!(s&4)||!check(x-1,x-3))&&!check(x-3,x)){ add(nxt[0][4|sig],now[0][s]); } if((s&2)&&(!(s&1)||!check(x-3,x-2))&&(!(s&4)||!check(x-1,x-3))){ add(nxt[1][3],now[0][s]); } if((s&4)&&(!(s&1)||!check(x-3,x-2))&&!check(x,x-3)){ add(nxt[0][2|sig],now[0][s]); } } void solve2(int x,int s){ int sig=s>>1&1; if((s&1)&&(!(s&4)||!check(x-2,x-3))&&!check(x-3,x)){ add(nxt[1][2|(sig<<2)],now[1][s]); } if((s&2)&&(!(s&1)||!check(x-3,x-1))&&(!(s&4)||!check(x-2,x-3))){ add(nxt[0][6],now[1][s]); } if((s&4)&&(!(s&1)||!check(x-3,x-1))&&!check(x,x-3)){ add(nxt[1][1|(sig<<2)],now[1][s]); } } int solve(){ if(D==0){ if(n==1)return 1; return 0; } if(D==1){ if(n==1)return 1; else if(n==2){ if(ban[1][2-1+3]||ban[2][1-2+3])return 0; return 1; } else{ return 0; } } if(D==2){ //最多只有两种情况 if(n==1)return 1; else if(n==2){ if(ban[2-1+3]||ban[1-2+3])return 0; return 1; } for(int i=1;i<=n;i+=2)state[i]=0; for(int i=2;i<=n;i+=2)state[i]=1; res+=check(); state[1]=0; for(int i=2;i<=n;i+=2)state[i]=0; for(int i=3;i<=n;i+=2)state[i]=1; res+=check(); return res; } if(n==1){ return 1; } if(n==2){ if(ban[2-1+3]||ban[1-2+3])return 0; return 1; } now[0][7]=now[1][7]=1; for(int i=4;i<=n;i++){ memset(nxt,0,sizeof nxt); for(int j=0;j<2;j++){ for(int k=0;k<8;k++){ if(now[j][k]){ if(j==0){ solve1(i,k); } else{ solve2(i,k); } } } } memcpy(now,nxt,sizeof nxt); } for(int i=0;i<2;i++){ for(int j=0;j<8;j++){ if(now[i][j]){ if(i==0){ if((!(j&1)||!check(n-2,n-1))&&(!(j&2)||!check(n-1,n))&&(!(j&4)||!check(n,n-2))){ add(res,now[i][j]); } } else{ if((!(j&1)||!check(n-2,n))&&(!(j&2)||!check(n,n-1))&&(!(j&4)||!check(n-1,n-2))){ add(res,now[i][j]); } } } } } return res; } int main(){ ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); cin>>n>>K>>D; for(int i=1;i<=K;i++){ int a,b;cin>>a>>b; if(abs(a-b)<=3){ ban[a][b-a+3]=1; } } cout<<solve(); }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17529973.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(24)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示