• [日常训练]游戏题


    ban

    Description
    n种英雄站成一列,要求每时每刻满足\(a_i\leq{a_{i+1}}\).
    两人轮流操作,每次可以ban任意多人人.
    问先手时候必胜.

    HINT
    \(n\leq10^5\).

    Solution
    这个条件有点麻烦...
    然后把数列差分一下,\(d_i=a_i-a_{i-1}\),发现ban第i种英雄k个等价于\(d_i-k,d_{i+1}+k\),这就转化成了阶梯Nim了.

    #define N 100005
    int a[N],n,t,ans;
    inline void Aireen(){
    	t=read();
    	while(t--){
    		n=read(); 
    		for(int i=1;i<=n;++i)
    			a[i]=read();
    		ans=0;
    		for(int i=n;i>=1;i-=2)
    			ans^=(a[i]-a[i-1]);
    		ans?puts("HH"):puts("GG"); 
    	} 
    }
    

    light

    Description
    给你一个\(n\times{n}\)的网格及每个网格中灯初始开关状态.
    可以对格子\((x,y)\)进行操作:改变\((x,y)\)及其上下左右四个格子的开关状态.
    求一种方案使得灯全关掉.

    HINT
    \(n^2\leq500\).

    Solution

    方法一

    枚举第一行的操作状态,O(nm)判是否可行.

    
    #define N 25
    int a[N][N],b[N][N],n;
    bool flag;
    inline bool chk(){
    	for(int i=1;i<n;++i){
    		for(int j=1;j<=n;++j){
    			if(a[i][j]^b[i][j]^b[i-1][j]^b[i][j-1]^b[i][j+1]) b[i+1][j]=1;
    			else b[i+1][j]=0;
    		}
    	}
    	for(int j=1;j<=n;++j)
    		if(a[n][j]^b[n][j]^b[n][j-1]^b[n-1][j]^b[n][j+1]) return false;
    	return true; 
    }
    inline void dfs(int u){
    	if(flag) return;
    	if(u>n){
    		if(chk()){
    			flag=true;
    			for(int i=1;i<=n;++i)
    				for(int j=1;j<=n;++j)
    					if(b[i][j]) printf("%d %d\n",i,j);
    			puts("0 0"); 
    		}
    		return;
    	}
    	b[1][u]=0;dfs(u+1);
    	b[1][u]=1;dfs(u+1);
    }
    inline void Aireen(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;++i)
    		for(int j=1;j<=n;++j)
    			scanf("%d",&a[i][j]);
    	dfs(1);
    }
    

    方法二

    将状态压成二进制判断.

    #define N 25
    int a[N],b[N],n;
    bool flag;
    inline bool chk(){
    	for(int i=1;i<n;++i)
    		b[i+1]=(a[i]^b[i-1]^b[i]^(b[i]<<1)^(b[i]>>1))&((1<<n)-1);
    	return !((a[n]^b[n-1]^b[n]^(b[n]<<1)^(b[n]>>1))&((1<<n)-1));
    }
    inline void dfs(int u,int k){
    	if(flag) return;
    	if(u>n){
    		b[1]=k; 
    		if(chk()){
    			flag=true;
    			for(int i=1;i<=n;++i)
    				for(int j=1;j<=n;++j)
    					if(b[i]&(1<<j-1)) printf("%d %d\n",i,j);
    			puts("0 0");
    		}
    		return;
    	}
    	dfs(u+1,k<<1);
    	dfs(u+1,k<<1|1);
    }
    inline void Aireen(){
    	n=read();
    	for(int i=1;i<=n;++i)
    		for(int j=1;j<=n;++j)
    			if(read()) a[i]|=1<<j-1;
    	
    	dfs(1,0);
    }
    

    方法三

    \(b_{i,j}\)表示\((i,j)\)的操作状态,则达成目标状态需要满足\(a_{i,j}\;xor\;b_{i,j}\;xor\;b_{i-1,j}\;xor\;b_{i+1,j}\;xor\;b_{i,j-1}\;xor\;b_{i,j+1}=0\).
    解方程组即可.

    #define N 25
    #define M 505
    int a[N][N],b[N][N],f[M][M],ans[M],n,cnt;
    inline void gauss(int n){
    	for(int i=1;i<n;++i){
    		if(!f[i][i]){
    			for(int j=i;j<n;++j)
    				if(f[j][i]){
    					for(int k=i;k<=n;++k)
    						swap(f[i][k],f[j][k]);
    				}
    		}
    		for(int j=1;j<n;++j)
    			if(i!=j&&f[j][i]){
    				for(int k=i;k<=n;++k)
    					f[j][k]^=f[i][k]; 
    			}
    	}
    	for(int i=1;i<n;++i)
    		ans[i]=f[i][n];
    } 
    inline void Aireen(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;++i)
    		for(int j=1;j<=n;++j)
    			scanf("%d",&a[i][j]);
    	for(int i=1;i<=n;++i)
    		for(int j=1;j<=n;++j)
    			b[i][j]=++cnt;
    	for(int i=1,k;i<=n;++i)
    		for(int j=1;j<=n;++j){
    			k=b[i][j];
    			f[k][k]=f[k][b[i][j-1]]=f[k][b[i-1][j]]\
    			  =f[k][b[i][j+1]]=f[k][b[i+1][j]]=1;
    			f[k][cnt+1]=a[i][j];
    		}
    	gauss(cnt+1);
    	for(int i=1,k;i<=n;++i)
    		for(int j=1;j<=n;++j)
    			if(ans[b[i][j]])
    				printf("%d %d\n",i,j);
    	puts("0 0"); 
    }
    

    ppt

    这道题真是$@#^#%...
    两头往中间匹配:
    尽量赢:小的尽量匹配比其小的,大的尽量匹配比其小的;不行的时候,用小的去换对方大的.
    尽量输:小的尽量匹配比其大的,大的尽量匹配比其大的;不行的时候,用大的去换对方小的.

    #define N 200005
    int a[N],b[N],n,ans;
    inline void Aireen(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;++i)
    		scanf("%d",&a[i]);
    	for(int i=1;i<=n;++i)
    		scanf("%d",&b[i]);
    	
    	sort(a+1,a+1+n);sort(b+1,b+1+n);
    	
    	for(int l=1,r=n,p=1,q=n;l<=r&&p<=q;){
    		while(a[l]>b[p]&&l<=r&&p<=q) ++l,++p,ans+=2;
    		while(a[r]>b[q]&&l<=r&&p<=q) --r,--q,ans+=2;
    		
    		if(l>r||p>q) break;
    		ans+=(a[l]==b[q]);++l;--q;
    	}
    	printf("%d ",ans);
    	ans=0;
    	for(int l=1,r=n,p=1,q=n;l<=r&&p<=q;){
    		while(a[l]<b[p]&&l<=r&&p<=q) ++l,++p;
    		while(a[r]<b[q]&&l<=r&&p<=q) --r,--q;
    		if(l>r||p>q) break;
    		ans+=2-(a[r]==b[p]);--r;++p;
    	}
    	printf("%d\n",ans);
    }
    

    2017-10-25 21:02:55

  • 相关阅读:
    行转列
    multipath 安装配置
    网卡绑定
    numa对MySQL多实例性能影响
    Fatal NI connect error 12170
    REVOKE DBA权限要小心
    Oracle 数据库整理表碎片
    listagg 函数
    10046 事件补充
    tkprof 解释
  • 原文地址:https://www.cnblogs.com/AireenYe/p/15602501.html
Copyright © 2020-2023  润新知