[GCJ2017R3]Cooclement
Posted skylee的OI博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[GCJ2017R3]Cooclement相关的知识,希望对你有一定的参考价值。
题目大意:
一种数列按照如下方式变化:
新数列第i位等于原数中数字i的出现次数。
变化过程中数列长度不变。
例如数列12的变化过程为12-11-20-01-10。
现在告诉你一个数列x,请求出x可能是有几种数列变化而来的。
思路:
将整个变化过程倒过来,除去自环就是一棵树。
题目就变成了求子树的大小。
显然枚举一个状态所有的前驱(即树上的子结点)会超时,只有25分。
然而如果只是求出一个状态对应的后继(父结点)会很简单。
我们可以枚举出所有的状态,然后求出其后继,最后拓扑排序时DP求出子树大小即可。
对于一些不存在的状态(各位数之和大于长度),我们则没必要遍历,可以特判判掉。
如果一个状态的所有前驱都是不存在的,我们可以直接用组合算出它前驱的数量。
1 #include<queue> 2 #include<cstdio> 3 #include<cctype> 4 #include<ext/hash_map> 5 int n; 6 inline int getint() { 7 register char ch; 8 n=1; 9 while(!isdigit(ch=getchar())); 10 register int x=ch^‘0‘; 11 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^‘0‘),n++; 12 return x; 13 } 14 const int N=10; 15 const int pow[]={1,10,100,1000,10000,100000,1000000,10000000,100000000}; 16 __gnu_cxx::hash_map<int,int> size[N]; 17 inline int fact(const int &n) { 18 int ret=1; 19 for(register int i=1;i<=n;i++) { 20 ret*=i; 21 } 22 return ret; 23 } 24 inline int comb(const int &n,const int &m) { 25 return fact(n-m); 26 } 27 __gnu_cxx::hash_map<int,int> deg[N]; 28 __gnu_cxx::hash_map<int,int> hash_table[N]; 29 int cnt[N]; 30 int hash(const int &n,const int &x) { 31 if(hash_table[n].count(x)) return hash_table[n][x]; 32 return hash_table[n][x]=++cnt[n]; 33 } 34 int nxt[N][50000]; 35 inline void add_edge(const int &n,const int &u,const int &v) { 36 nxt[n][hash(n,u)]=hash(n,v); 37 deg[n][hash(n,v)]++; 38 } 39 void dfs2(const int now,const int &n) { 40 int next=0,tmp=now; 41 while(tmp) { 42 next+=tmp%10?pow[n-tmp%10]:0; 43 tmp/=10; 44 } 45 if(next==now) { 46 size[n][now]--; 47 return; 48 } 49 add_edge(n,now,next); 50 } 51 void dfs(const int cur,const int &n,const int now,const int sum) { 52 if(sum>n) return; 53 if(cur==n) { 54 if(!sum||size[n].count(hash(n,now))) return; 55 int &ans=size[n][hash(n,now)]; 56 int nn=n,num=now; 57 ans=fact(nn); 58 while(num) { 59 ans/=fact(num%10); 60 nn-=num%10; 61 num/=10; 62 } 63 ans/=fact(nn); 64 ans++; 65 dfs2(now,n); 66 return; 67 } 68 for(int i=0;i<=n;i++) { 69 dfs(cur+1,n,(((now<<2)+now)<<1)+i,sum+i); 70 } 71 } 72 int main() { 73 int T=getint(); 74 for(register int i=1;i<=T;i++) { 75 const int x=getint(); 76 int tmp=x,sum=0; 77 while(tmp) { 78 sum+=tmp%10; 79 tmp/=10; 80 } 81 if(sum>n) { 82 printf("Case #%d: %d\n",i,1); 83 continue; 84 } 85 if(size[n].empty()) { 86 dfs(0,n,0,0); 87 std::queue<int> q; 88 for(register int j=1;j<=cnt[n];j++) { 89 if(!deg[n][j]) { 90 q.push(j); 91 } else { 92 size[n][j]=1; 93 } 94 } 95 while(!q.empty()) { 96 const int x=q.front(); 97 q.pop(); 98 size[n][nxt[n][x]]+=size[n][x]; 99 if(!--deg[n][nxt[n][x]]) q.push(nxt[n][x]); 100 } 101 } 102 printf("Case #%d: %d\n",i,size[n][hash(n,x)]); 103 } 104 return 0; 105 }
以上是关于[GCJ2017R3]Cooclement的主要内容,如果未能解决你的问题,请参考以下文章