题目大意:
  一种数列按照如下方式变化:
  新数列第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的更多相关文章

随机推荐

  1. 【洛谷P2015】二叉苹果树

    题目描述 有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点) 这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1. 我们用一根树枝两端连接的结点的编号来 ...

  2. [POI 2008&洛谷P3467]PLA-Postering 题解(单调栈)

    [POI 2008&洛谷P3467]PLA-Postering Description Byteburg市东边的建筑都是以旧结构形式建造的:建筑互相紧挨着,之间没有空间.它们共同形成了一条长长 ...

  3. MyBatis笔记之配置输出日志并打印输出SQL语句

    1. 引入Log4J的Maven依赖: <dependency> <groupId>log4j</groupId> <artifactId>log4j& ...

  4. Git其他的命令------(四)

    git除了在工作当中可以进行对代码进行管理的设置之外,git的其他指令也偶尔会被用到~ 1:删除某一个文件:   rm -rf node,然后按下tab 2:查看修改文件的修改的详细信息:  git ...

  5. tp5 r3 一个简单的SQL语句调试实例

    tp5 r3 一个简单的SQL语句调试实例先看效果核心代码 public function index() { if (IS_AJAX && session("uid&quo ...

  6. SurfaceFlinger 讲解

    SurfaceFlinger是Android multimedia的一个部分,在Android 的实现中它是一个service,提供系统 范围内的surface composer功能,它能够将各种应用 ...

  7. netif_start_queue/netif_wake_queue/netif_stop_queue

    在网卡驱动中,内核为发送数据包的流量控制提供了几个主要的函数,用来在驱动程序和内核之间传递流控信息. 主要有4个: 1]netif_start_queue  启动接口传输队列 2]netif_wake ...

  8. python使用unittest模块selenium访问斗鱼获取直播信息

    import unittest from selenium import webdriver from bs4 import BeautifulSoup as bs class douyu(unitt ...

  9. 谷歌PageRank算法

    1. 从Google网页排序到PageRank算法 (1)谷歌网页怎么排序? 先对搜索关键词进行分词,如“技术社区”分词为“技术”和“社区”: 根据建立的倒排索引返回同时包含分词后结果的网页: 将返回 ...

  10. 监控MYSQL主从同步配置中监控从库运行状态的脚本

    代码如下: #!/bin/bash #Check MySQL Slave's Runnning Status #Crontab time 00:10 MYSQLPORT=`netstat -na|gr ...