Crash 的文明世界
Description
Crash 小朋友最近迷上了一款游戏——文明5(Civilization V)。在这个游戏中,玩家可以建立和发展自己的国家,通过外交和别的国家交流,或是通过战争征服别的国家。现在Crash 已经拥有了一个N 个城市的国家,这些城市之间通过道路相连。由于建设道路是有花费的,因此Crash 只修建了N-1 条道路连接这些城市,不过可以保证任意两个城市都有路径相通。在游戏中,Crash 需要选择一个城市作为他的国家的首都,选择首都需要考虑很多指标,有一个指标是这样的:
其中S(i)表示第i 个城市的指标值,dist(i, j)表示第i 个城市到第j 个城市需要经过的道路条数的最小值,k 为一个常数且为正整数。因此Crash 交给你一个简单的任务:给出城市之间的道路,对于每个城市,输出这个城市的指标值,由于指标值可能会很大,所以你只需要输出这个数mod 10007 的值。
Input
输入的第一行包括两个正整数N 和k。下面有N-1 行,每行两个正整数u、v (1 ≤ u, v ≤ N),表示第u 个城市和第v 个城市之间有道路相连。这些道路保证能符合题目的要求。
Output
输出共N 行,每行一个正整数,第i 行的正整数表示第i 个城市的指标值 mod 10007 的值。
Sample Input
5 2
1 2
1 3
2 4
2 5
Sample Output
10
7
23
18
18
HINT
20%的数据满足N ≤ 5000、k ≤ 30。
50%的数据满足N ≤ 50000、k ≤ 30。
100%的数据满足N ≤ 50000、k ≤ 150。
【特别注意】由于数据大小限制为5MB,我只好对测试时的输入文件进行压缩处理。下面的函数可以将压缩的输入文件转化为原始输入文件。(函数从infile 中读入压缩的输入文件,将解压缩后的输入文件输出到outfile 中)
C/C++版本:
void Uncompress(FILE *infile, FILE *outfile)
{
int N, k, L, i, now, A, B, Q, tmp;
fscanf(infile, "%d%d%d", &N, &k, &L);
fscanf(infile, "%d%d%d%d", &now, &A, &B, &Q);
fprintf(outfile, "%d %d\n", N, k);
for (i = 1; i < N; i ++)
{
now = (now * A + B) % Q;
tmp = (i < L) ? i : L;
fprintf(outfile, "%d %d\n", i - now % tmp, i + 1);
}
}
Pascal 版本:
procedure Uncompress(var infile, outfile : text);
var N, k, L, i, now, A, B, Q, tmp : longint;
begin
read(infile, N, k, L, now, A, B, Q);
writeln(outfile, N, ' ', k);
for i := 1 to N - 1 do
begin
now := (now * A + B) mod Q;
if i < L
then tmp := i
else
tmp := L;
writeln(outfile, i - now mod tmp, ' ', i + 1);
end;
end;
下面给出一个具体的例子。
civiliazation_compressed.in 表示压缩的输入文件, civilization.in 表示解压缩后的输入文件。
civilization_compressed.in
7 26 4 29643 2347 5431 54209
civilization.in
7 26 1 2 2 3 2 4 3 5 4 6 5 7
2016.2.19重设时限为10s
来练习使用stirling数~
难题一道.jpg
思路:
考虑这个k次幂非常恶心,那么把它拆开。
令
考虑把颜色相同的物体分到一类里,那么有
xk=∑i=1k{ki}∗xi−
右边的意思是,枚举方案中出现了的颜色的个数i,并将这
注意这里的
然后对于下降幂我们同样可以继续转化:
xk−=(xk)∗k!
左边代表,用x种颜色给
右边代表,从x种颜色中选出
那么现在有
xk=∑i=1k{ki}∗(xi)∗i!
于是xk便被拆开了!
可以发现stirling数可以最后再乘进去,不如提出来。
令f[i][j]=∑k=1n(dist(i,k)j),
那么答案便可以表示为ansi=∑j=1k{kj}∗j!∗f[i][j]。
考虑f[i][j]的转移,可以发现f[i][j]=∑k∈ch[i]f[k][j]+f[k][j−1]。
直接转移即可!
注意,上面的f[i][j]建立在i为根节点的前提下,否则向父亲节点方向的子树需要单独特殊考虑,这里使用了另一个数组
大功告成!
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int x=0;char ch=getchar();
while(ch<'0' || '9'<ch)ch=getchar();
while('0'<=ch && ch<='9')x=x*10+(ch^48),ch=getchar();
return x;
}
const int N=50009;
const int K=159;
const int md=10007;
int n,k;
int to[N<<1],nxt[N<<1],beg[N],tot;
int fa[N],siz[N],f[N][K],g[N][K];
int s[K][K],fac[K];
inline void adde(int u,int v)
{
to[++tot]=v;
nxt[tot]=beg[u];
beg[u]=tot;
}
inline void add(int &a,int b)
{
if(b>=md)b-=md;a+=b;if(a>=md)a-=md;
}
inline void init()
{
s[0][0]=fac[0]=1;
for(int i=1;i<K;i++)
{
fac[i]=(long long)fac[i-1]*i%md;
s[i][0]=0;s[i][i]=1;
for(int j=1;j<i;j++)
s[i][j]=(j*s[i-1][j]%md+s[i-1][j-1])%md;
}
}
inline void normal()
{
n=read();k=read();
for(int i=1,u,v;i<n;i++)
{
u=read();v=read();
adde(u,v);adde(v,u);
}
}
inline void dfs(int u)
{
f[u][0]=1;
for(int i=beg[u];i;i=nxt[i])
if(to[i]!=fa[u])
{
fa[to[i]]=u;
dfs(to[i]);
for(int j=1;j<=k;j++)
add(f[u][j],f[to[i]][j-1]+f[to[i]][j]);
add(f[u][0],f[to[i]][0]);
}
}
inline void dfs2(int u)
{
g[u][0]=n-f[u][0];
for(int i=beg[u],v;i;i=nxt[i])
if((v=to[i])!=fa[u])
{
for(int j=1;j<=k;j++)
{
add(g[v][j],((g[u][j-1]+g[u][j]+f[u][j]+f[u][j-1]-f[v][j]-f[v][j-1]*2)%md+md)%md);
if(j>=2)add(g[v][j],-f[v][j-2]+md);
}
dfs2(to[i]);
}
}
int main()
{
init();
decompressed();
dfs(1);
dfs2(1);
for(int i=1;i<=n;i++)
{
int ans=0;
for(int j=1;j<=k;j++)
add(ans,(long long)(g[i][j]+f[i][j])%md*fac[j]%md*s[k][j]%md);
printf("%d\n",ans);
}
return 0;
}

本文针对游戏《文明5》中的城市指标值计算问题,提出了一种有效的算法解决方案。该算法利用了组合数学中的Stirling数,通过对问题的巧妙转换,实现了高效计算。文章详细介绍了从问题定义到最终实现的全过程。
1262

被折叠的 条评论
为什么被折叠?



