zoukankan      html  css  js  c++  java
  • bzoj 2159: Crash 的文明世界

    Time Limit: 10 Sec  Memory Limit: 259 MB
    Submit: 480  Solved: 234
    [Submit][Status][Discuss]

    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, k); for (i = 1; i < N; i ++) { now = (now * A + B) % Q; tmp = (i < L) ? i : L; fprintf(outfile, "%d %d ", 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


    为什么要把输入改成这鬼样,,,,害得我一开始没看见RE。。。。

    咳咳现在讲一下正解。
    首先S(i)=Σdist(i,j)^k,这个看起来贼迷,但是我们有一个公式:
    x^k=Σ(i=1 to k)  S(k,i)*P(x,i),  其中S是第二类斯特林数,P是排列数。

    这样的话我们把这个套进S(i)里,就是:
    S(i)=Σ(h=1 to k)S(k,h)*ΣP(dist(j,i),h),  又因为P(i,j)=C(i,j)*j!,所以变成C之后上式就是:
    S(i)=Σ(h=1 to k)S(k,h)*h!*ΣC(dist(j,i),h)   。。。
    貌似又陷入僵局了 ???
    并不,后面的那个Σ是可以递推出来的,因为C(x,y)=C(x-1,y-1)+C(x-1,y).
    所以我们设now[x][i]=ΣC(dist(x,v),i),其中v是以x为根的子树中的一点;
    up[x][i]=ΣC(dist(x,v),i),其中v是以x为根的子树外的一点。

    显然now[x][0]=1+Σnow[v][0], 因为任意C(g,0)都为1。
    up[x][0]=n-now[x][0],因为显然子树内的点数+子树外的点数=n。

    然后可以发现的是now[x][i]=Σ(now[v][i]+now[v][i-1]),其中v在以x为根的子树中。
    这个不难理解,根据now的定义就可以推出。

    主要是推up有一点小麻烦。
    我们分类的话(设fa为x在树上的父亲),不在x为根的子树中的点无非分为两种:
        1.不在以fa为根的子树中的节点。
        2.在以fa为根的子树的不在以x为根的子树中的节点。

    1的贡献就是up[fa][i-1]+up[fa][i],2的贡献就是{ now[fa][i]-(now[x][i]+now[x][i-1]) }+{ now[fa][i-1]-(now[x][i-1]+now[x][i-2]) }。

    所以两次dfs就可以解决,最后把前面Σ后面的系数乘上加进答案就ojbk了。

    code:

     1 #include<bits/stdc++.h>
     2 #define maxn 50005
     3 #define ll long long
     4 #define ha 10007
     5 #define pb push_back
     6 using namespace std;
     7 vector<int> g[maxn];
     8 int now[maxn][160],n,up[maxn][160],k;
     9 int uu,vv,ans,S[160][160],jc[160];
    10  
    11 inline void init(){
    12     jc[0]=1;
    13     for(int i=1;i<=155;i++) jc[i]=jc[i-1]*i%ha;
    14     S[0][0]=1;
    15     for(int i=1;i<=155;i++){
    16     //  S[i][0]=1;
    17         for(int j=1;j<=i;j++) S[i][j]=(S[i-1][j-1]+S[i-1][j]*j)%ha;
    18     }
    19 }
    20  
    21 void dfs1(int x,int fa){
    22     int to;
    23     now[x][0]=1;
    24     for(int i=g[x].size()-1;i>=0;i--){
    25         to=g[x][i];
    26         if(to==fa) continue;
    27         dfs1(to,x);
    28         now[x][0]+=now[to][0];
    29         for(int j=1;j<=k;j++){
    30             now[x][j]+=now[to][j]+now[to][j-1];
    31             while(now[x][j]>=ha) now[x][j]-=ha;
    32         }
    33         up[x][0]=n-now[x][0];
    34     }
    35 }
    36  
    37 void dfs2(int x,int fa){
    38     int to;
    39     if(fa){
    40         for(int i=1;i<=k;i++){
    41             up[x][i]=(up[fa][i]+up[fa][i-1]+now[fa][i]+now[fa][i-1]-now[x][i-1]*2-now[x][i]);
    42             if(i>1) up[x][i]-=now[x][i-2];
    43             up[x][i]=up[x][i]%ha+ha;
    44             if(up[x][i]>=ha) up[x][i]-=ha;
    45         }
    46     }
    47      
    48     for(int i=g[x].size()-1;i>=0;i--){
    49         to=g[x][i];
    50         if(to==fa) continue;
    51         dfs2(to,x);
    52     }
    53 }
    54  
    55 int main(){
    56     init();
    57     int L,NOW,A,B,Q;
    58     scanf("%d%d%d%d%d%d%d",&n,&k,&L,&NOW,&A,&B,&Q);
    59     for(int i=1;i<n;i++){
    60         NOW=(NOW*A+B)%Q;
    61         int tmp=i<L?i:L;
    62         uu=i-NOW%tmp,vv=i+1;
    63         g[uu].pb(vv),g[vv].pb(uu);
    64     }
    65      
    66     dfs1(1,1);
    67     dfs2(1,0);
    68      
    69     for(int i=1;i<=n;i++){
    70         ans=0;
    71         for(int j=1;j<=k;j++) ans=(ans+S[k][j]*jc[j]%ha*(now[i][j]+up[i][j]))%ha;
    72         printf("%d
    ",ans);
    73     }
    74     return 0;
    75 }
    我爱学习,学习使我快乐
  • 相关阅读:
    WCF 转 武胜
    NET(C#):GetHashCode不需要太复杂 转 武胜
    wcf KnownTypeAttribute 武胜
    memmove
    李开复谈创业失败十原因:经不住诱惑 直接山寨
    Linux使用Wine 安装source insight
    VM 中ubuntu下Eclipse ctrl+s 显示update conflict的问题
    ISO/OSI模型
    memset函数使用详解
    C语言中字符串的处理方式
  • 原文地址:https://www.cnblogs.com/JYYHH/p/8215288.html
Copyright © 2011-2022 走看看