[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的更多相关文章
随机推荐
- VC进度条的使用
m_progress->GetPos(); //获取进度条的当前位置 m_progress->GetRange(int min,int max); //获取进度条控件的范围的下限和上限 m ...
- CRF++模板使用(转)
CRF++模板构建分为两类,一类是Unigram标注,一类是Bigram标注. Unigram和Bigram模板分别生成CRF的状态特征函数 和转移特征函数 .其中 是标签, 是观测序列, ...
- 一文掌握关于Java数据结构所有知识点(欢迎一起完善)
在我们学习Java的时候,很多人会面临我不知道继续学什么或者面试会问什么的尴尬情况(我本人之前就很迷茫).所以,我决定通过这个开源平台来帮助一些有需要的人,通过下面的内容,你会掌握系统的Java学习以 ...
- xv6/bootasm.S + xv6/bootmain.c
xv6/bootasm.S #include "asm.h" #include "memlayout.h" #include "mmu.h" ...
- Deep Learning基础--Softmax求导过程
一.softmax函数 softmax用于多分类过程中,它将多个神经元的输出,映射到(0,1)区间内,可以看成概率来理解,从而来进行多分类! 假设我们有一个数组,V,Vi表示V中的第i个元素,那么这个 ...
- openjudge-NOI 2.6-2718 移动路线
题目链接:http://noi.openjudge.cn/ch0206/2718/ 题解: 递推,某一个点只能从其左边或者下边走过来 f[i][j]存储(i,j)这个点上的结果,即f[i][j]=f[ ...
- WDCP各种停止重启命令
service wdapache start|stop|restart wdcp后台 启动|停止|重起service nginxd start|stop|restart nginx ...
- nginx 服务器篇
Nginx 服务器类型 1. Web服务器 Web服务器用于提供HTTP(包括HTTPS)的访问,例如Nginx.Apache.IIS等. 2. 应用程序服务器 应用程序服务器能够用于应用程序的运行, ...
- 网页查看源码中<div>的含义
代码如下: /** HTML转义 **/ String s = HtmlUtils.htmlEscape("<div>hello world</div><p&g ...
- chkconfig命令主要用来更新(启动或停止)和查询系统服务的运行级信息
chkconfig命令主要用来更新(启动或停止)和查询系统服务的运行级信息.谨记chkconfig不是立即自动禁止或激活一个服务,它只是简单的改变了符号连接. 使用语法:chkconfig [--ad ...