• [URAL1540]Battle for the Ring


    I.[URAL1540]Battle for the Ring

    这大约是我做的第一道SG函数的题(

    很容易想到一个区间DP状态:设 \(f_{i,j,k}\) 表示第 \(i\) 条链子,\([j,k]\) 这一段的SG值。

    于是我们枚举这一段中删掉了小于等于某个值的元素进行转移。如果删掉的值形成了多个串,依照SG函数的性质,取值应是其异或。

    但是这题因为需要保证复杂度在 \(O(kn^3)\) 以内,所以大概不能太随性地转移。我采取的方法是,因为每一个 \(f_{i,j,k}\) 都是一个集合 \(g_{i,j,k}\) 中的 \(\text{mex}\),所以我们考虑由 \(g_{i,j,k-1}\) 推出 \(g_{i,j,k}\),这是可以在 \(O(n)\) 之内解决的。于是复杂度就是严格 \(O(kn^3)\),但是有一大坨细节。如果允许带个 \(\log\),那就可以非常简单地用类珂朵莉树的结构维护,但是我没敢试(

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    int n,res;
    const int LIM=100;
    struct Chain{
    	int a[110],f[110][110],len,g[110][110],las[110][110],mn[110][110];
    	bool occ[110];
    	void read(){scanf("%d",&len);for(int i=1;i<=len;i++)scanf("%d",&a[i]);}
    	void DP(){
    		memset(mn,0x3f,sizeof(mn));
    		for(int i=len;i;i--)for(int j=i;j<=len;j++){
    			mn[i][j]=min(mn[i][j-1],a[j]);
    			for(int k=1;k<=LIM;k++){
    				if(a[j]<=k){g[j][k]=g[j-1][k];continue;}
    				if(i==j||a[j-1]<=k){las[j][k]=j,g[j][k]=g[j-1][k]^1;continue;}
    				g[j][k]=g[j-1][k]^f[las[j-1][k]][j-1]^f[las[j-1][k]][j],las[j][k]=las[j-1][k];
    			}
    //			printf("(%d %d)\n",i,j);
    			for(int k=1;k<=LIM;k++)occ[k]=false;
    			for(int k=mn[i][j];k<=LIM;k++)occ[g[j][k]]=true;
    			for(int k=0;k<=LIM;k++)if(!occ[k]){f[i][j]=k;break;}
    			for(int k=1;k<mn[i][j];k++)g[j][k]=f[i][j];
    //			printf("%d\n",f[i][j]);
    		}
    	}
    	int ALL(){return f[1][len];}
    	int CHECK(){
    		res^=f[1][len];
    //		printf("%d\n",res);
    		for(int i=1;i<=len;i++){
    			int tot=0;
    			for(int j=1,k=1;j<=len;j=k){
    				if(a[j]<=a[i]){k++;continue;}
    				k=j;while(k<=len&&a[k]>a[i])k++;
    				tot^=f[j][k-1];
    			}
    //			printf("%d:%d\n",i,tot);
    			if(tot==res)return i;
    		}
    		res^=f[1][len];
    		return -1;
    	}
    }c[60];
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)c[i].read(),c[i].DP(),res^=c[i].ALL();
    	if(!res){puts("S");return 0;}
    	puts("G");
    	for(int i=1;i<=n;i++){
    		int tmp=c[i].CHECK();
    		if(tmp==-1)continue;
    		printf("%d %d\n",i,tmp);
    		return 0;
    	}
    	return 0;
    }
    
  • 相关阅读:
    69道Java Spring 面试&笔试题
    不少程序员都会遇到的三个问题
    Java中main方面面试题
    学生成绩表(对成绩的操作)
    Eclipse常用快捷键
    java 调用打印机 打印服务
    java 打开浏览器 url
    java 邮件发送 apache commons-email
    java 邮件收发 (只能输入英文,中文需要转码)
    jquery 画板折叠
  • 原文地址:https://www.cnblogs.com/Troverld/p/14605770.html
Copyright © 2020-2023  润新知