• IOI2021集训队作业 226AE Maze Reduction


    一个图,找出所有等价的点的集合。

    等价的点即:两个点(A,B)分别开始走,每次可以选一条边走,可以分辨点的度数,可以知道来到一个点的前驱边是谁,能够分辨出连出去的边的顺时针顺序。如果没有办法分辨这两个点,这两个点就是等价的。

    (nle 100)


    哈希就能过了。。。

    (f_{k,i,j})表示从点(i)开始先走第(j)条边进行探索,探索了(k)步的哈希值。

    转移记下点前驱边开始(包括前驱边,如果不包括可能没有地方探索,导致全零的假象)顺时针转,形成的哈希值。

    比较点(x)(y)时,将(f_{n,x})(f_{n,y})的最小表示法对比一下。

    由于不会最小表示法,直接比较所有循环同构串哈希值的最小值,也能过。


    using namespace std;
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <climits>
    #define N 105
    #define ll long long
    #define mo 998244353
    #define jd 19260817
    ll qpow(ll x,ll y){
    	ll r=1;
    	for (;y;y>>=1,x=x*x%mo)
    		if (y&1)
    			r=r*x%mo;
    	return r;
    }
    int n;
    int e[N][N],ne[N];
    int re[N][N];
    int f[N][N][N];
    int vis[N];
    int idc[N];
    int minidc(int a[],int k){
    	static int q[N*2];
    	memcpy(q,a,sizeof(int)*k);
    	memcpy(q+k,a,sizeof(int)*k);
    	ll key=0,tmp=qpow(jd,k),res=INT_MAX;
    	for (int i=0;i<k;++i)
    		key=(key*jd+q[i])%mo;
    	for (int i=k;i<k*2;++i){
    		key=((key*jd+q[i])%mo-tmp*q[i-k]%mo+mo)%mo;
    		res=min(res,key);
    	}
    	return res;
    }
    bool same(int x,int y){
    	if (ne[x]!=ne[y]) return 0;
    	return idc[x]==idc[y];
    }
    int main(){
    	freopen("in.txt","r",stdin);
    	scanf("%d",&n);
    	for (int i=1;i<=n;++i){
    		scanf("%d",&ne[i]);
    		for (int j=0;j<ne[i];++j){
    			scanf("%d",&e[i][j]);
    			re[i][e[i][j]]=j;
    		}
    	}
    	for (int i=1;i<=n;++i)
    		for (int j=0;j<ne[i];++j)
    			f[0][i][j]=ne[i];
    	for (int k=1;k<=n;++k)
    		for (int i=1;i<=n;++i)
    			for (int j=0;j<ne[i];++j){
    				int y=e[i][j];
    				ll key=0;
    				for (int t=re[y][i];t<ne[y];++t)
    					key=(key*jd+f[k-1][y][t])%mo;
    				for (int t=0;t<re[y][i];++t)
    					key=(key*jd+f[k-1][y][t])%mo;
    				f[k][i][j]=key;
    			}
    	for (int i=1;i<=n;++i)
    		idc[i]=minidc(f[n][i],ne[i]);
    //	for (int i=1;i<=n;++i){
    //		printf("i=%d : %d
    ",i,idc[i]);
    //		for (int j=0;j<ne[i];++j)
    //			printf("%d ",f[n][i][j]);
    //		printf("
    ");
    //	}
    	int bz=0;
    	for (int i=1;i<=n;++i)
    		if (!vis[i]){
    			vis[i]=1;
    			static int q[N];
    			int k=1;
    			q[1]=i;
    			for (int j=i+1;j<=n;++j)
    				if (!vis[j] && same(i,j)){
    					vis[j]=1;
    					q[++k]=j;
    				}
    			if (k>1){
    				for (int j=1;j<=k;++j)
    					printf("%d ",q[j]);
    				printf("
    ");
    				bz=1;
    			}
    		}
    	if (bz==0)
    		printf("none
    ");
    	return 0;
    }
    
  • 相关阅读:
    Linux中的MyEclipse配置Hadoop
    C#学习笔记(三)
    关于读博,关于成为一个专家
    C#查找子串在原串中出现次数
    C#学习笔记(二)
    Matlab中sortrows函数解析
    C#学习笔记(一)
    甘特图与网络图
    ubuntu开启SSH服务
    分词错误重点分析这几项
  • 原文地址:https://www.cnblogs.com/jz-597/p/13966386.html
Copyright © 2020-2023  润新知