[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的更多相关文章
随机推荐
- flex实例(阮一峰)
Flex 布局教程:实例篇 作者: 阮一峰 日期: 2015年7月14日 上一篇文章介绍了Flex布局的语法,今天介绍常见布局的Flex写法. 你会看到,不管是什么布局,Flex往往都可以几行命令 ...
- 【C++自我精讲】基础系列六 PIMPL模式
[C++自我精讲]基础系列六 PIMPL模式 0 前言 很实用的一种基础模式. 1 PIMPL解释 PIMPL(Private Implementation 或 Pointer to Implemen ...
- 常见的bug
常见bug 一. Android系统功能测试设计的测试用例: a.对所测APP划分模块 b.详细列出每个模块的功能点(使用Xmind绘制功能图) c.使用等价类划分.边界值.场景法等对各功能点编写测试 ...
- weblogic 包里面有中文文件名 会报错
目前:没有解决,只要有中文启动就报错 http://bbs.csdn.net/topics/10055670 http://www.2cto.com/os/201406/311394.html
- php webshell常见函数
0x1 直接在字符串变量后面加括号, 会调用这个函数: <?php $s = 'system'; $e = 'assert'; $s('whoami'); $e('phpinfo();'); 0 ...
- 37 - 网络编程-UDP编程
目录 1 UDP协议 2 UDP通信流程 3 UDP编程 3.1 构建服务端 3.3 常用方法 4 聊天室 5 UDP协议应用 1 UDP协议 UDP是面向无连接的协议,使用UDP协议时,不需要建立连 ...
- 78.PL和PS通过BRAM交互共享数据
本篇文章目的是使用Block Memory进行PS和PL的数据交互或者数据共享,通过zynq PS端的Master GP0端口向BRAM写数据,然后再通过PS端的Mater GP1把数据读出来,将结果 ...
- tomcat+java的web程序持续占cpu高问题调试【转】
转自 tomcat+java的web程序持续占cpu问题调试 - 像风一样的自由 - CSDN博客http://blog.csdn.net/five3/article/details/28416771 ...
- Codeforces Round #502
Codeforces Round #502 C. The Phone Number 题目描述:求一个\(n\)排列,满足\(LIS+LDS\)最小 solution 枚举\(LIS\),可证明\(LD ...
- java.lang.IllegalArgumentException: Page directive: invalid value for import
我的项目原来用的tomcat版本是apache-tomcat-7.0.53,后来为了安全原因将版本升至\apache-tomcat-7.0.57,发现有的jsp页面出现下面的异常: java.lang ...