[GCJ2017R3]Cooclement
题目大意:
一种数列按照如下方式变化:
新数列第i位等于原数中数字i的出现次数。
变化过程中数列长度不变。
例如数列12的变化过程为12-11-20-01-10。
现在告诉你一个数列x,请求出x可能是有几种数列变化而来的。
思路:
将整个变化过程倒过来,除去自环就是一棵树。
题目就变成了求子树的大小。
显然枚举一个状态所有的前驱(即树上的子结点)会超时,只有25分。
然而如果只是求出一个状态对应的后继(父结点)会很简单。
我们可以枚举出所有的状态,然后求出其后继,最后拓扑排序时DP求出子树大小即可。
对于一些不存在的状态(各位数之和大于长度),我们则没必要遍历,可以特判判掉。
如果一个状态的所有前驱都是不存在的,我们可以直接用组合算出它前驱的数量。
#include<queue>
#include<cstdio>
#include<cctype>
#include<ext/hash_map>
int n;
inline int getint() {
register char ch;
n=;
while(!isdigit(ch=getchar()));
register int x=ch^'';
while(isdigit(ch=getchar())) x=(((x<<)+x)<<)+(ch^''),n++;
return x;
}
const int N=;
const int pow[]={,,,,,,,,};
__gnu_cxx::hash_map<int,int> size[N];
inline int fact(const int &n) {
int ret=;
for(register int i=;i<=n;i++) {
ret*=i;
}
return ret;
}
inline int comb(const int &n,const int &m) {
return fact(n-m);
}
__gnu_cxx::hash_map<int,int> deg[N];
__gnu_cxx::hash_map<int,int> hash_table[N];
int cnt[N];
int hash(const int &n,const int &x) {
if(hash_table[n].count(x)) return hash_table[n][x];
return hash_table[n][x]=++cnt[n];
}
int nxt[N][];
inline void add_edge(const int &n,const int &u,const int &v) {
nxt[n][hash(n,u)]=hash(n,v);
deg[n][hash(n,v)]++;
}
void dfs2(const int now,const int &n) {
int next=,tmp=now;
while(tmp) {
next+=tmp%?pow[n-tmp%]:;
tmp/=;
}
if(next==now) {
size[n][now]--;
return;
}
add_edge(n,now,next);
}
void dfs(const int cur,const int &n,const int now,const int sum) {
if(sum>n) return;
if(cur==n) {
if(!sum||size[n].count(hash(n,now))) return;
int &ans=size[n][hash(n,now)];
int nn=n,num=now;
ans=fact(nn);
while(num) {
ans/=fact(num%);
nn-=num%;
num/=;
}
ans/=fact(nn);
ans++;
dfs2(now,n);
return;
}
for(int i=;i<=n;i++) {
dfs(cur+,n,(((now<<)+now)<<)+i,sum+i);
}
}
int main() {
int T=getint();
for(register int i=;i<=T;i++) {
const int x=getint();
int tmp=x,sum=;
while(tmp) {
sum+=tmp%;
tmp/=;
}
if(sum>n) {
printf("Case #%d: %d\n",i,);
continue;
}
if(size[n].empty()) {
dfs(,n,,);
std::queue<int> q;
for(register int j=;j<=cnt[n];j++) {
if(!deg[n][j]) {
q.push(j);
} else {
size[n][j]=;
}
}
while(!q.empty()) {
const int x=q.front();
q.pop();
size[n][nxt[n][x]]+=size[n][x];
if(!--deg[n][nxt[n][x]]) q.push(nxt[n][x]);
}
}
printf("Case #%d: %d\n",i,size[n][hash(n,x)]);
}
return ;
}
[GCJ2017R3]Cooclement的更多相关文章
随机推荐
- 郑轻校赛 2127 tmk射气球 (数学)
Description 有一天TMK在做一个飞艇环游世界,突然他发现有一个气球匀速沿直线飘过,tmk想起了他飞艇上有一把弓,他打算拿弓去射气球,为了提高射击的准确性,他首先在飞艇上找到一个离气球最近的 ...
- Shader -> Photoshop图层混合模式计算公式大全
Photoshop图层混合模式计算公式大全 混合模式可以将两个图层的色彩值紧密结合在一起,从而创造出大量的效果,在这些效果的背后实际是一些简单的数学公式在起作用. 下面是photoshop cs2中所 ...
- 仿360影视网站模板html
链接:http://pan.baidu.com/s/1mhIkV4s 密码:9wgq
- Nginx部署部分https与部分http【转】
转自 Nginx部署部分https与部分http - na_tion的专栏 - 博客频道 - CSDN.NEThttp://blog.csdn.net/na_tion/article/details/ ...
- 在shell中如何判断字符串是否为有效的IP地址【转】
转自 在shell中如何判断字符串是否为有效的IP地址_echoisecho_新浪博客http://blog.sina.com.cn/s/blog_53a844e50100xxus.html 近来需要 ...
- 135.Candy---贪心
题目链接 题目大意:分糖果,每个小朋友都有一个ratings值,且每个小朋友至少都要有一个糖果,而且每个小朋友的ratings值如果比左右邻舍的小朋友的ratings值高,则其糖果数量也比邻舍的小朋友 ...
- DAG blockchain (byteball)
转载参考自: https://www.jinse.com/bitcoin/116184.html https://www.jinse.com/blockchain/116175.html https: ...
- ansible报错Aborting, target uses selinux but python bindings (libselinux-python) aren't installed
报错内容: TASK [activemq : jvm configuration] ********************************************************** ...
- PostGIS 操作geometry方法
WKT定义几何对象格式: POINT(0 0) ——点 LINESTRING(0 0,1 1,1 2) ——线 POLYGON((0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2 ...
- GPS位置模拟-安卓
测试定位功能时都需要位置模拟,一般有如下3种方式: a)手机上安装第三方模拟软件:需要Root: b)PC模拟其中运行app并模拟位置:不能在真机上运行,手机兼容性不能测试到: b)在app中让开发增 ...