省选模拟35
A. Board Game
发现 \(nm\) 很小,可以状压存下状态
用一个 \(vis\) 数组来记录当前状态是否能结束
再用一个 \(f\) 数组来转移是否先手必胜
转移都很简单,每次枚举一个位置就能转移了
不想写压位,于是就大力卡常
用 \(\text{lowbit}\) 来枚举在当前状态和不在当前状态的位置
再循环展开 \(8\) 次来加速(实测只有 \(8\) 次管用, \(4\) 次或者 \(16\) 次都会降低速度)
再及时 \(\text{break}\) 一下,加个 \(register\) 就可以通过
要是时限 \(1s\) 的话只用第一个优化就足以通过
赛时用的 \(SG\) 函数和题解的 \(dp\) 没啥区别,但是要慢一些
Code
#include<bits/stdc++.h>
//#define int long long
#define rint signed
#define meow(args...) fprintf(stderr,args)
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
int n,m,k,U;
int id[30][30],tot;
bool vis[134217728],f[134217728];
signed main(){
#ifdef LOCAL
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
n=read(),m=read(),k=read();U=(1<<(n*m))-1;
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) id[i][j]=tot++;
for(int i=1,h,w,vsta;i<=k;i++){
h=read(),w=read();vsta=0;
for(int i=1;i<=h;i++) for(int j=1,v;j<=w;j++){scanf("%1d\n",&v);vsta|=v<<id[i][j];}
for(int i=1;i<=n-h+1;i++) for(int j=1;j<=m-w+1;j++) vis[vsta<<id[i][j]]=1;
}
for(register int sta=0,vsta,v;sta<=U;){
if(!vis[sta]){vsta=sta;while(vsta){v=vsta&-vsta,vsta^=v;if(vis[sta]=vis[sta^v]) break;}}sta++;
if(!vis[sta]){vsta=sta;while(vsta){v=vsta&-vsta,vsta^=v;if(vis[sta]=vis[sta^v]) break;}}sta++;
if(!vis[sta]){vsta=sta;while(vsta){v=vsta&-vsta,vsta^=v;if(vis[sta]=vis[sta^v]) break;}}sta++;
if(!vis[sta]){vsta=sta;while(vsta){v=vsta&-vsta,vsta^=v;if(vis[sta]=vis[sta^v]) break;}}sta++;
if(!vis[sta]){vsta=sta;while(vsta){v=vsta&-vsta,vsta^=v;if(vis[sta]=vis[sta^v]) break;}}sta++;
if(!vis[sta]){vsta=sta;while(vsta){v=vsta&-vsta,vsta^=v;if(vis[sta]=vis[sta^v]) break;}}sta++;
if(!vis[sta]){vsta=sta;while(vsta){v=vsta&-vsta,vsta^=v;if(vis[sta]=vis[sta^v]) break;}}sta++;
if(!vis[sta]){vsta=sta;while(vsta){v=vsta&-vsta,vsta^=v;if(vis[sta]=vis[sta^v]) break;}}sta++;
}
for(register int sta=U,vsta,v;~sta;){
if(!vis[sta]){vsta=U^sta;while(vsta){v=vsta&-vsta,vsta^=v;if(f[sta]=!f[sta^v]) break;}}sta--;
if(!vis[sta]){vsta=U^sta;while(vsta){v=vsta&-vsta,vsta^=v;if(f[sta]=!f[sta^v]) break;}}sta--;
if(!vis[sta]){vsta=U^sta;while(vsta){v=vsta&-vsta,vsta^=v;if(f[sta]=!f[sta^v]) break;}}sta--;
if(!vis[sta]){vsta=U^sta;while(vsta){v=vsta&-vsta,vsta^=v;if(f[sta]=!f[sta^v]) break;}}sta--;
if(!vis[sta]){vsta=U^sta;while(vsta){v=vsta&-vsta,vsta^=v;if(f[sta]=!f[sta^v]) break;}}sta--;
if(!vis[sta]){vsta=U^sta;while(vsta){v=vsta&-vsta,vsta^=v;if(f[sta]=!f[sta^v]) break;}}sta--;
if(!vis[sta]){vsta=U^sta;while(vsta){v=vsta&-vsta,vsta^=v;if(f[sta]=!f[sta^v]) break;}}sta--;
if(!vis[sta]){vsta=U^sta;while(vsta){v=vsta&-vsta,vsta^=v;if(f[sta]=!f[sta^v]) break;}}sta--;
}
puts(f[0]?"Alice":"Bob");
return 0;
}
B. Function Query
打表发现规律,除掉 \(gcd\) 后,两数相加为 \(2^k\) 时有贡献
于是预处理出所有的转移位置,再扫描线维护答案
Code
#include<bits/stdc++.h>
#define int long long
#define rint signed
#define lowbit(x) x&-x
#define meow(args...) fprintf(stderr,args)
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
int n,q;
int BIT[100010];
int a[100010],pos[100010],ans[100010];
int vis[100010];
vector<pair<int,int>>vec[100010],u[100010];
inline void upd(int x,int k){for(;x;x-=lowbit(x)) BIT[x]+=k;}
inline int query(int x){int res=0;for(;x<=n;x+=lowbit(x)) res+=BIT[x];return res;}
int gcd(int x,int y){return (!y)?x:gcd(y,x%y);}
int F(int x,int y){
if(x==y) return 1;int v=abs(x-y);
return F(x+y-v,v)+1;
}
signed main(){
#ifdef LOCAL
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
freopen("func.in","r",stdin);
freopen("func.out","w",stdout);
n=read();for(int i=1;i<=n;i++) pos[a[i]=read()]=i;
q=read();
for(int i=1,l,r;i<=q;i++){
l=read(),r=read();
vec[r].emplace_back(make_pair(l,i));
}
for(int k=1,v;(1<<k)<=(n<<1);k++){
for(int i=1;i<=(1<<k-1);i++) if(i!=(v=(1<<k)-i)){
if(i>v) continue;
if(gcd(i,v)==1){
for(int c=1;c*v<=n;c++){
if(pos[c*i]<pos[c*v]) u[pos[c*v]].emplace_back(pos[c*i],F(c*i,c*v));
if(pos[c*i]>pos[c*v]) u[pos[c*i]].emplace_back(pos[c*v],F(c*i,c*v));
}
}
}
}
for(int i=1;i<=n;i++){
for(auto L:u[i]) upd(L.first,L.second);
for(auto L:vec[i]) ans[L.second]=query(L.first);
}
for(int i=1;i<=q;i++) printf("%lld\n",ans[i]);
return 0;
}
C. Minimal DFA
咕咕咕