• The 2014 ACM-ICPC Asia Xi'an Regional Contest — F题 Color


    觉得这题真要总结一下,先贴一个半AC的代码(还有组合数超时问题)。

    1)西安赛场上我们推出了一个dp方程:

    定义前i个位置使用了j种颜色的花(一共备选m种):

    边界是F(1,1) = m,答案是F(n, k)。很显然直接递推的方式是O(nk)的复杂度,显然受不了。然后我们很sb的在赛场上搞各种矩阵快速幂压缩方法,106的矩阵,最后这个dp方程成功铸铁。

    2)不这样想应该怎么思考呢?如果我们换一个角度,让N个位置固定,

    凭直觉我们能想出C(m, k) * k * (k-1)n-1这么一个式子,对不对呢?显然它是能保证相邻两朵花不同颜色了,但并不能保证刚好用k朵花(例如有花1、2、3,K=3,N=3,那么121也被计算在内了)。

    难道做不通了么?。。。如果将F[i, j]定义为在i朵备选花中,选j朵的方案数:

    这是一个方法,因为它的复杂度终于跟M和N无关了,我们对它进行化简和二项式反演:

     

     期望时间O(K2),还是不行。

    3)在群里问,并且验证过的,最终的解法是:

    F[k] = C(m, k) * k * (k-1)n-1-F[k-1]

    ans = F[k]

    期望时间O(K),这个需要证明

    。。然后我证不出来,然后然后就没有然后了。。

      1 #include <cstdio>
      2 #include <cstring>
      3 using namespace std;
      4 
      5 typedef long long LL;
      6 const int mod = 1e9+7;
      7 
      8 int pow_mod(int p, int k)
      9 {
     10     LL ans = 1;    
     11     while(k) {
     12         if (k & 1) ans = ans * p % mod;
     13         p = (LL)p*p % mod;
     14         k >>= 1;
     15     }
     16     return ans;
     17 }
     18 
     19 //以下为求逆元
     20 ///*************//
     21 LL extend_gcd(LL a,LL b,LL &x,LL &y)
     22 {
     23     if(b==0)
     24     {
     25         x=1;
     26         y=0;
     27         return a;
     28     }
     29     LL gcd=extend_gcd(b,a%b,x,y);
     30     LL t=x;
     31     x=y;
     32     y=t-a/b*x;
     33     return gcd;
     34 }
     35 LL Get_Inverse(LL num)
     36 {
     37     LL x,y;
     38     extend_gcd(num,mod,x,y);
     39     return (x%mod+mod)%mod;
     40 }
     41 ///*************//
     42 LL comb(LL n,LL m)//计算组合数C(n,m)
     43 {
     44     LL t1=1,t2=1;
     45     for(LL i=n;i>m;i--)
     46     {
     47         t1=(t1*i)%mod;
     48         t2=(t2*(i-m))%mod;
     49     }
     50     return t1*Get_Inverse(t2)%mod;
     51 }
     52 
     53 
     54 /* 
     55 int dp[10007][10007];
     56 
     57 LL dfs(int N, int m, int k) {
     58     if (~dp[m][k]) return dp[m][k];
     59     LL ans = 0;
     60     for(int j = 1; j<k; ++j)
     61         ans = (ans + dfs(N, k,j)) % mod;
     62     return dp[m][k] = (comb(m, k)*(((LL)k*pow_mod(k-1, N-1) % mod - ans) % mod)) % mod;
     63 }*/ 
     64 
     65 int k_kdec[100007];
     66 
     67 int main(void)
     68 {
     69     int T;
     70     scanf("%d", &T);
     71 
     72     for(int t=1; t<=T; ++t) {
     73         int N, M, K;
     74         scanf("%d%d%d", &N, &M, &K);
     75         // memset(dp, -1, sizeof dp);
     76         // 暴力
     77         // printf("%d
    ", dfs(N, M, K));
     78         /*
     79         for(int m=1; m<=K; ++m) {
     80             k_kdec[m] = 0;
     81             for(int k=1; k<m; ++k)
     82                 k_kdec[m] = (k_kdec[m] + (comb(m, k) * ((LL)k*pow_mod(k-1, N-1) % mod)) % mod) % mod;
     83         }
     84         // 二项式反演
     85         int sgn[] = {1, -1};
     86         int bk = 0;
     87         for(int k = 1; k<=K; ++k)
     88             bk = (bk +(sgn[(K-k) & 1] * (comb(K, k) * k_kdec[k]) % mod)) % mod;
     89         printf("%I64d
    ", (comb(M, K) * (((LL)K*pow_mod(K-1, N-1) % mod) - bk) % mod) % mod);*/
     90         
     91         // 容斥直接搞 
     92         LL ans = 0;
     93         int sgn = 1;
     94         for(int k = K; k>=1; --k) {
     95             ans = (ans + sgn * ((comb(M, k) * ((LL)k*pow_mod(k-1, N-1) % mod)) % mod)) % mod;
     96             sgn = -sgn;
     97         }
     98         printf("Case #%d: %d
    ", t, (int)ans);
     99     }
    100 }
  • 相关阅读:
    Oracle 修改带数据的字段类型
    Oracle的主键约束、唯一约束与外键约束
    Oracle 唯一 索引 约束 创建 删除
    Oracle 在Drop表时的Cascade Constraints
    iTunes备份注意
    谈判的四种风格
    求平均速度
    网站推荐的代码自动生成软件实际使用感触
    DOTA游戏相关的文章
    魔兽争霸3不能弹出输入法原因
  • 原文地址:https://www.cnblogs.com/e0e1e/p/xian2014_F.html
Copyright © 2020-2023  润新知