省选模拟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

咕咕咕

posted @ 2022-03-21 21:59  Max_QAQ  阅读(37)  评论(0编辑  收藏  举报