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 }
題意
定義一個序列,前兩項是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 }
題意
給出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 }