题目大意:
  一种数列按照如下方式变化:
  新数列第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. 【洛谷 P4166】 [SCOI2007]最大土地面积(凸包,旋转卡壳)

    题目链接 又调了我两个多小时巨亏 直接\(O(n^4)\)枚举4个点显然不行. 数据范围提示我们需要一个\(O(n^2)\)的算法. 于是\(O(n^2)\)枚举对角线,然后在这两个点两边各找一个点使 ...

  2. C - A New Function (整除分块 + 玄学优化)

    题目链接:https://cn.vjudge.net/contest/270608#problem/C 题目大意:给你一个n,让你求从1->n中间每个数的因子之和(每个数在求因子的过程中不包括本 ...

  3. Sqlmap与burpsuite动态更新某些参数

    有如下注入点: http://localhost/id=1&order_nu=1 情况说明: id为注入点,  每一次注入时, order_nu不能跟上次的一样(假说这个order_nu为一个 ...

  4. CounterBreach安装测试的全部过程

    CounterBreach安装测试的全部过程 1安装数据库审计的网关 Admin进入 Impcfg初始化 选择网关 是否替换另一个网关? 否 是否改变默认管理口 设置管理口地址 192.168.1.2 ...

  5. python基础之常用内置函数

    前言 python有许多内置的函数,它们定义在python的builtins模块,在python的代码中可以直接使用它们. 常用的内置函数 类型转换 int python的整数类型都是int类型的实例 ...

  6. shell脚本自带变量的含义

    $0 Shell本身的文件名 $1-$n 添加到Shell的各参数值.$1是第1参数.$2是第2参数… $$ Shell本身的PID(ProcessID) $! Shell最后运行的后台Process ...

  7. 头像截图上传三种方式之一(一个简单易用的flash插件)(asp.net版本)

    flash中有版权声明,不适合商业开发.这是官网地址:http://www.hdfu.net/ 本文参考了http://blog.csdn.net/yafei450225664/article/det ...

  8. java版云笔记(二)

    云笔记 基本的环境搭建好了,今天做些什么呢,第一是链接数据库(即搭建Spring-Batistas环境),第二是登录预注册. 注:这个项目的sql文件,需求文档,需要的html文件,jar包都可以去下 ...

  9. c++鼠标点点,获取坐标值,放入到txt文件中

    // oj3.cpp : Defines the entry point for the console application.// #include "stdafx.h"#in ...

  10. oracle相关命令收集-张

    orcle相关命令收集 1,用管理员登陆 /as sysdba:2, 更改用户密码 alter user name identified by password: alter user exptest ...