1. 程式人生 > >2014-2015 ACM-ICPC, Asia Xian Regional Contest(部分題解)

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\n",t++); 20 else 21 printf("Case #%d: Yes\n",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\n", 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\n", ca, ans);
67     }
68     return 0;
69 }

 

Color