codeforces #295 div1

2015-03-02 22:19:15

总结:比赛就做了个A,题意比较晦涩,难度中等... 24minAC(速度中等-。-)

  QUQ 回到紫名辣,哈哈~

  ※:比赛中想到了B的解法,死活wa4,赛后改了改TLE,最终把vector换成数组,AC了。

     然后,把C题给补了。

A:核心在于考虑到s中的每个字符会与t中的每个字符匹配n次。

   统计一下s中A,C,G,T这四个字符每个字符的出现次数c1~c4。

  可以发现,如果有个字符出现次数大于其他字符,那么构造的t串肯定都由该字符组成,t仅有1种。

  然后进一步,如果出现次数最大的字符有两个,那么构造的t串肯定由这两个字符组成,t有2^n种。

  同理,如果出现次数最大的字符有三个,t有3^n种....。如果四个字符出现次数相等,t有4^n种。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cmath>
 5 #include <vector>
 6 #include <map>
 7 #include <set>
 8 #include <stack>
 9 #include <queue>
10 #include <string>
11 #include <iostream>
12 #include <algorithm>
13 using namespace std;
14 
15 #define MEM(a,b) memset(a,b,sizeof(a))
16 #define REP(i,n) for(int i=1;i<=(n);++i)
17 #define REV(i,n) for(int i=(n);i>=1;--i)
18 #define FOR(i,a,b) for(int i=(a);i<=(b);++i)
19 #define RFOR(i,a,b) for(int i=(a);i>=(b);--i)
20 #define getmid(l,r) ((l) + ((r) - (l)) / 2)
21 #define MP(a,b) make_pair(a,b)
22 
23 typedef long long ll;
24 typedef pair<int,int> pii;
25 const int INF = (1 << 30) - 1;
26 const ll MOD = 1e9 + 7;
27 
28 int n;
29 char s[100010];
30 int cnt[10];
31 
32 ll Q_pow(int x,int y){
33     ll res = 1,X = x;
34     while(y){
35         if(y & 1) res = (res * X) % MOD;
36         y >>= 1;
37         X = (X * X) % MOD;
38     }
39     return res;
40 }
41 
42 bool cmp(int a,int b){
43     return a > b;
44 }
45 
46 int main(){
47     scanf("%d",&n);
48     scanf("%s",s + 1);
49     for(int i = 1; i <= n; ++i){
50         if(s[i] == 'A') cnt[1]++;
51         else if(s[i] == 'C') cnt[2]++;
52         else if(s[i] == 'G') cnt[3]++;
53         else cnt[4]++;
54     }
55     sort(cnt + 1,cnt + 4 + 1,cmp);
56     if(cnt[1] > cnt[2]) printf("1\n");
57     else if(cnt[1] == cnt[2] && cnt[2] > cnt[3])
58         printf("%I64d\n",Q_pow(2,n));
59     else if(cnt[1] == cnt[2] && cnt[2] == cnt[3] && cnt[3] > cnt[4])
60         printf("%I64d\n",Q_pow(3,n));
61     else printf("%I64d\n",Q_pow(4,n));
62     return 0;
63 }
View Code

 

B:我承认这题我的代码有点繁琐....

  思路的话还是比较清晰的,用一种类似拓扑排序的方法,用队列保存当前可以取的格子。

  然后看当前是第一个人取还是第二个人取,如果是第一个人取那么取编号最大的格子,第二个人取编号最小的格子。

  上述,我用两个优先队列来实现(这里会涉及到重复取的问题,所以开一个数组标记一下某个编号的格子是否被取掉了。)

  上述,用set实现即可,用迭代器遍历的set天然有序,begin()取出最小值,end()的前一个位置取出最大值。

  用up[maxn][3],down[maxn][3]来记录格子上方和下方的格子编号。

  然后写两个函数,remove用来取掉某个格子,check用来检查格子当前是否可取。

  注意:一个坑点在于,当前可以取的格子在以后不一定能取,所以每次从优先队列里top()出来的格子都要check了以后再取。

 

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cstdlib>
  4 #include <cmath>
  5 #include <vector>
  6 #include <map>
  7 #include <set>
  8 #include <stack>
  9 #include <queue>
 10 #include <string>
 11 #include <iostream>
 12 #include <algorithm>
 13 using namespace std;
 14 
 15 #define MEM(a,b) memset(a,b,sizeof(a))
 16 #define REP(i,n) for(int i=1;i<=(n);++i)
 17 #define MP(a,b) make_pair(a,b)
 18 
 19 typedef long long ll;
 20 typedef pair<int,int> pii;
 21 const ll mod = 1e9 + 9;
 22 
 23 set<int> st;
 24 map< pii,int > mp;
 25 int m;
 26 int v[100010][2];
 27 int ans[100010],anscnt;
 28 int up[100010][3],down[100010][3];
 29 
 30 bool check(int a){
 31     for(int i = 0; i < 3; ++i) if(up[a][i]){
 32         int id = up[a][i],cnt = 0;
 33         for(int j = 0; j < 3; ++j) cnt += !down[id][j];
 34         if(cnt == 2) return false;
 35     }
 36     return true;
 37 }
 38 
 39 void Remove(int a){
 40     int now,id;
 41     for(int i = 0; i < 3; ++i){
 42         if(up[a][i]){
 43             id = up[a][i];
 44             for(int j = 2; j >= 0; --j)
 45                 if(down[id][j] == a) down[id][j] = 0;
 46         }
 47         if(down[a][i]){
 48             id = down[a][i];
 49             for(int j = 2; j >= 0; --j)
 50                 if(up[id][j] == a) up[id][j] = 0;
 51         }
 52     }
 53 }
 54 
 55 void Topo(){
 56     for(int i = 1; i <= m; ++i) if(check(i)) st.insert(i);
 57     int cur = 1;
 58     set<int>::iterator it;
 59     while(!st.empty()){
 60         int x;
 61         if(cur % 2){ //qmax
 62             it = st.end();
 63             it--;
 64             x = (*it);
 65             st.erase(x);
 66         }
 67         else{
 68             it = st.begin();
 69             x = (*it);
 70             st.erase(x);
 71         }
 72         if(check(x) == false) continue;
 73         cur++;
 74         ans[++anscnt] = x;
 75         int tem[3] = {down[x][0],down[x][1],down[x][2]};
 76         Remove(x);
 77         for(int i = 0; i < 3; ++i) if(tem[i] && check(tem[i])) st.insert(tem[i]);
 78     }
 79 }
 80 
 81 int main(){
 82     scanf("%d",&m);
 83     REP(i,m){
 84         scanf("%d%d",&v[i][0],&v[i][1]);
 85         mp[MP(v[i][0],v[i][1])] = i;
 86     }
 87     REP(i,m){
 88         int id,a = v[i][0],b = v[i][1];
 89         //down
 90         if(mp.find(MP(a - 1,b - 1)) != mp.end())    down[i][0] = mp[MP(a - 1,b - 1)];
 91         if(mp.find(MP(a,b - 1)) != mp.end())    down[i][1] = mp[MP(a,b - 1)];
 92         if(mp.find(MP(a + 1,b - 1)) != mp.end())    down[i][2] = mp[MP(a + 1,b - 1)];
 93         //up
 94         if(mp.find(MP(a - 1,b + 1)) != mp.end())    up[i][0] = mp[MP(a - 1,b + 1)];
 95         if(mp.find(MP(a,b + 1)) != mp.end())    up[i][1] = mp[MP(a,b + 1)];
 96         if(mp.find(MP(a + 1,b + 1)) != mp.end())    up[i][2] = mp[MP(a + 1,b + 1)];
 97     }
 98     Topo();
 99     ll rlt = 0;
100     for(int i = 1; i <= anscnt; ++i)    rlt = (rlt * m % mod + ans[i] - 1) % mod;
101     printf("%I64d\n",rlt);
102     return 0;
103 }
View Code

  

C:计算每个数的贡献。

  枚举每个数在个位 / 百位/ 千位 / 万位... 依次计算贡献。

  为了加速计算,要先求一个前缀和。

  那么接下来就比较好搞了。

  比如我要求每个数在百位的贡献,我们需要分两种情况:

  (1) ans += digit[倒数第二位] * 10^1 * Combination(n - 2,k)

  (2) ans += sum[n - i] * 10^1 * Combination(n - 3,k - 1)

  之所以分两类,因为第一类计算的是最后一个可能在百位上的数的贡献,第二类计算的是其余的可能在百位上的数的贡献。

  如果我们要使某一位数在百位,那么肯定要在这个数后面一个数的后面加一个'+',唯一的特例就是倒数第二数(天然地就是百位)所以分两类。

  然后,(1)中Combination(n - 2,k)的意思是最后两个数之间不能插'+',其余n-2个位置间插k个'+'。(2)中Combination(n - 3,k - 1)的意思是首先我要在该位

     数后面一个数的后面插'+',然后这两个数之间不能插'+',那么剩下的k-1个'+'插在n-3个位置中。

  注意:组合数比较大,要用逆元预处理阶乘,然后计算过程中计算组合数。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cmath>
 5 #include <vector>
 6 #include <map>
 7 #include <set>
 8 #include <stack>
 9 #include <queue>
10 #include <string>
11 #include <iostream>
12 #include <algorithm>
13 using namespace std;
14 
15 #define MEM(a,b) memset(a,b,sizeof(a))
16 #define REP(i,n) for(int i=1;i<=(n);++i)
17 #define REV(i,n) for(int i=(n);i>=1;--i)
18 #define FOR(i,a,b) for(int i=(a);i<=(b);++i)
19 #define RFOR(i,a,b) for(int i=(a);i>=(b);--i)
20 #define getmid(l,r) ((l) + ((r) - (l)) / 2)
21 #define MP(a,b) make_pair(a,b)
22 
23 typedef long long ll;
24 typedef pair<int,int> pii;
25 const int INF = (1 << 30) - 1;
26 const ll MOD = 1e9 + 7;
27 
28 int n,k;
29 ll sum[100010];
30 ll ten[100010];
31 ll fac[100010],afac[100010];
32 char s[100010];
33 
34 ll Q_pow(int x,int y){
35     ll res = 1,X = x;
36     while(y){
37         if(y & 1) res = (res * X) % MOD;
38         X = (X * X) % MOD;
39         y >>= 1;
40     }
41     return res;
42 }
43 
44 void Pre(){
45     fac[0] = afac[0] = 1;
46     REP(i,n){
47         fac[i] = (fac[i - 1] * (ll)i) % MOD;
48         afac[i] = Q_pow(fac[i],MOD - 2);
49     }
50     ten[0] = 1;
51     REP(i,n) ten[i] = ten[i - 1] * 10LL % MOD;
52     return ;
53 }
54 
55 ll Comb(int n,int m){
56     if(n < m) return 0;
57     return fac[n] * afac[n - m] % MOD * afac[m] % MOD;
58 }
59 
60 int main(){
61     scanf("%d%d",&n,&k);
62     scanf("%s",s + 1);
63     REP(i,n) sum[i] = (sum[i - 1] + s[i] - '0') % MOD;
64     if(k == 0){
65         ll ans = 0;
66         REP(i,n) ans = (ans * 10LL % MOD + s[i] - '0') % MOD;
67         printf("%I64d\n",ans);
68         return 0;
69     }
70     Pre();
71     ll ans = 0;
72     REP(i,n){ //位数
73         ans = (ans + (ll)(s[n - i + 1] - '0') * ten[i - 1] % MOD * 
74                 Comb(n - i,k) % MOD) % MOD;
75         ans = (ans + (ll)sum[n - i] * ten[i - 1] % MOD * 
76                 Comb(n - i - 1,k - 1) % MOD) % MOD;
77     }
78     printf("%I64d\n",ans);
79     return 0;
80 }
View Code

 

posted @ 2015-03-02 22:52  Naturain  阅读(180)  评论(0编辑  收藏  举报