• 2014-2015 ACM-ICPC, Asia Xian Regional Contest(部分题解)


    摘要

      本文主要给出了2014-2015 ACM-ICPC, Asia Xian Regional Contest的部分题解,说明了每题的题意、解题思路和代码实现,意即熟悉区域赛比赛题型。


    Built with Qinghuai and Ari Factor

    题意

    判断是否是Q数列,只要数列中每个数均能够被3整除就是Q数列。

    解题思路

    需要特判一下0的情况。

    代码

     1 #include <cstdio>
     2 
     3 int main()
     4 {
     5     int T;
     6     int n;
     7     int t = 1;
     8     scanf("%d", &T);
     9     while(T--) {
    10         scanf("%d", &n);
    11         int f = 0;
    12         int x;
    13         for(int i = 0; i < n; i++) {
    14             scanf("%d", &x);
    15             if(x == 0 || x % 3 != 0 )
    16                 f = 1;
    17         }
    18         if(f)
    19             printf("Case #%d: No
    ",t++);
    20         else
    21             printf("Case #%d: Yes
    ",t++);
    22     }
    23     return 0;
    24 }

    Last Defence

    题意

      定义一个序列,前两项是a和b,第三项是前两项之差的绝对值,然后依次类推,问会出现多少个不同的数字。

    解题思路

      首先能够想到的是该数列最终会呈现...,x,0,x,0这样的序列,但是出现过多少个不同的数字呢,其实给出a和b后,不妨将a写成kb + tmp的形式,其中不同的数字个数就是k个,因为每次相减后出现一个(k - 1)* b + tmp,总共有k个,但这只是一组(相当于减到底),下一组就是b = a % b,a = b,直到b等于0的的时候,就可以结束了,最后再加上0这个数字的1个。

      注意考虑特殊情况,当a == 0 且b != 0 或者 b == 0 且 a != 0时 sum = 2;

               当a = b = 0时,sum = 1;

    代码

     1 #include <cstdio>
     2 typedef long long ll;
     3 
     4 int main()
     5 {
     6     int T, t = 1;
     7     scanf("%d", &T);
     8     ll a, b, tmp, sum;
     9     while(T--) {
    10         scanf("%lld %lld", &a, &b);
    11         if(a == 0 && b == 0)
    12             sum = 1;
    13         else if((a == 0 && b != 0) || (a != 0 && b == 0))
    14             sum = 2;
    15         else {
    16             sum = 1;
    17             tmp = 1;
    18             while(tmp) {
    19                 sum += a / b;
    20                 tmp = a % b;
    21                 a = b;
    22                 b = tmp;
    23             }
    24         }
    25         printf("Case #%d: %lld
    ", t++, sum);
    26     }
    27     return 0;
    28 }

    Color

    题意

      给出n朵花,排成一行,问从m种颜色中挑出k种染色,使得这n朵花使用恰好k种颜色的同时两个相邻的话不同颜色,有多少种不同的方案。

    解题思路

      不难从m中颜色重挑出k中颜色,即C(m, k)。然后计算恰好使用k种颜色去染着n朵花,容易写出C(m, k) * k * (k - 1)^(n - 1)种方法,但是仔细想一下,这计算了最多使用k种颜色染的方案数,包含重复计数,这里就要考虑容斥了,假设最多使用 i 种颜色的方案数为F[i],那么其中包括了最多使用 i-1 种的,最多使用 i-1 种的里面又包含了最多使用 i-2 种的,以此类推得到

      ans = C(m, k) * (F[k] - (F[k - 1] - (F[k - 2] - (... - (F[3] - (F[2] - F[1])))))) = C(m, k) * (F[k] - F[k - 1] + F[k - 2] - ... + (-1)^(k - i)F[i] + (-1)^(k -2)F[2] + (-1)^(k - 1)F[1]),其中F[i]根据之前的计算方法等于(-1)^(k - i) * C(k, i) * (k - i)^(n - 1) 。
      也可以看下表

      

      如果减去f[i-1]的话,相当于减去整个表格里的内容:一个 i-1, 两个 i-2, 三个 i-3 .....所以因为减去了两个i-2,所以需要把i-2加回来一个,所以  + f[i-2] 就行了,其他同理 ,即可解释容斥原理。举个例子,如果选取的k个颜色是1,2,3,4,会有一种染色方案是1,2,1,2...,如果选取的k-1个颜色是1,2,3,仍然会包含一种染色方案1,2,1,2...所以上面的公式要再加上颜色数<=(k-2)的方案数,然后再减去颜色数<=(k-3)的方案数。

      剩下的就是具体实现的细节了,首先怎么快速计算C(m, k)和C(k, i)?使用递推的方式,公式推导如下

      

      然后其中使用到了乘法逆元。

      最后就是了解一下输入输出外挂(不加也可以A)。

    代码如下

     1 #include <cctype>
     2 #include <cstdio>
     3 
     4 typedef long long ll;
     5 const int mod = 1e9 + 7;
     6 const int maxk = 1e6 + 7;
     7 
     8 ll Sca() {
     9     ll res = 0, f = 0;
    10     char x = getchar();
    11     if(x == '-')
    12         f = 1;
    13     if(x >= '0' && x <= '9')
    14         res = x - '0';
    15     while((x = getchar()) >= '0' && x <= '9')
    16         res = res * 10 + (x - '0');
    17     return f ? -res : res;
    18 }
    19 void Out(ll x) {
    20     if(x > 9)
    21         Out(x / 10);
    22     putchar(x % 10 + '0');
    23 }
    24 ll qpow(ll x, ll n) {
    25     ll ans = 1;
    26     while(n) {
    27         if(n & 1)
    28             ans = ans * x % mod;
    29         x = x * x % mod;
    30         n >>= 1;
    31     }
    32     return ans;
    33 }
    34 ll inv[maxk];
    35 void get_inv() {
    36     for(ll i = 1; i < maxk; i++) {
    37         inv[i] = qpow(i, mod - 2);
    38     }
    39 }
    40 ll ck[maxk], cm[maxk];
    41 void get_c(ll m, ll k) {
    42     cm[0] = ck[0] = 1;
    43     for(ll i = 1; i <= k; i++) {
    44         cm[i] = (cm[i - 1] * (m - i + 1) % mod) * inv[i] % mod ;
    45         ck[i] = (ck[i - 1] * (k - i + 1) % mod) * inv[i] % mod;
    46     }
    47 }
    48 int main()
    49 {
    50     get_inv();
    51     ll T;
    52     T = Sca();
    53     ll n, m, k;
    54     for(ll ca = 1; ca <= T; ca++) {
    55         n = Sca();
    56         m = Sca();
    57         k = Sca();
    58 
    59         get_c(m, k);
    60         ll ans = 0;
    61         ll f = 1;
    62         for(ll i = k; i >= 1; i--, f = -f) {
    63             ans = (ans + (f * ck[i] * i % mod * qpow(i - 1, n - 1) % mod) + mod) % mod;
    64         }
    65         ans = ans * cm[k] % mod;
    66         printf("Case #%lld: %lld
    ", ca, ans);
    67     }
    68     return 0;
    69 }

    Color

  • 相关阅读:
    P1967 货车运输【最大生成树+倍增LCA】!!!
    P1991 无线通讯网【kruskal】
    P2872 [USACO07DEC]Building Roads S【kruskal】
    最小生成树
    树的直径
    树的重心
    今日英语单词小结
    项目生命周期
    反射reflect(框架的基石),动态导入小技巧 | 元类 | 单例设计模式
    OOP的三大特征之多态 | 面向对象高级知识,内置魔法函数,点语法和[ ]取值的实现,运算符重载,迭代器协议,上下文管理
  • 原文地址:https://www.cnblogs.com/wenzhixin/p/9996981.html
Copyright © 2020-2023  润新知