TopCoder 603 div1 & div2

div2

250pts MiddleCode

 题意:s串长度为奇数时,将中间字符取掉并添加到t末尾;长度为偶数时,将中间两个较小的字符取掉并添加到末尾。

分析:直接做,学习了一下substr(s, pos, len)返回s中从pos开始的长度为len的字串。

代码:

 1 class MiddleCode {
 2 public:
 3     void Remove(string &s, int pos) {
 4         int len = s.size();
 5         string t = "";
 6         if(pos < 0 || pos >= len) return;
 7         for(int i = 0; i < len; i++)
 8             if(i != pos) t += s[i];
 9         s = t;
10     }
11     string encode(string s) {
12         int n = s.size(), m = n;
13         string ans = "";
14         for(int i = 0; i < n; i++) {
15             if((n-i)&1) {
16                 ans += s[(n-i)/2];
17                 Remove(s, (n-i)/2);
18             } else {
19                 if(s[(n-i)/2] < s[(n-i)/2-1]) {
20                     ans += s[(n-i)/2];
21                     Remove(s, (n-i)/2);
22                 } else {
23                     ans += s[(n-i)/2-1];
24                     Remove(s, (n-i)/2-1);
25                 }
26             }
27         }
28         return ans;
29     }
30 };
View Code

 

500pts SplitIntoPairs

题意:将N个数(偶数)分成N/2组,使得两个数的乘积>=X的组数尽量多,X < 0。

分析:X < 0,所以只有当每组的两个数A,B一正一负时才有可能比X小,将N个数分成负数和非负数两组,如果负数有偶数个,那么结果就是N/2组,

因为负数,正数可以分别两两配对。当为奇数的时候,负数和正数两两配对正好剩下一个,且绝对值应该尽量小,判断两数之积和X的关系即可。

代码:

 1  class SplitIntoPairs {
 2 public:
 3     int makepairs(vector <int> A, int X) {
 4 //       int n = sz(A);
 5        sort(A.begin(), A.end());
 6        vector<int> B, C;
 7        for(int i = 0; i < sz(A); i++){
 8            if(A[i] >= 0) B.pb(A[i]);
 9            else C.pb(A[i]);
10        }
11        int n = sz(B), m = sz(C);
12        if(n%2 == 0) return (n+m)/2;
13        return (n+m)/2-(1LL*C[m-1]*B[0] < X);
14     }
15 };
View Code

 

950pts GraphWalkWithProbabilities

 题意:从一点出发,每一轮选择任意可达的点,该点有win[i], lose[i], 1-win[i]-lose[i]三个概率, 表示到达该点赢,输,继续的概率,从Start出发,

按照最优的走法,最后赢d的概率。

分析:从某一点x出发能够赢得概率和转移到相邻的点y,然后赢的概率有关,但是图中可能存在环,因此采用记忆化搜索的话,

会存在相互依赖关系构成环的情况,转移到一个点y要能够继续进行的话概率为-win[y]-lose[y],那么可以设从y出发,最多进行steps轮,最后能够赢得概率。

这样转移dp[node][steps] = max{ win[to] + (1-win[to]-lose[to]) * dp[to][steps-1] };

steps上界设为3000左右即可,因为1-win[to]-lose[to]最大0.99, 最多3000轮,最终赢得概率应该是能满足题目精度要求的。

代码:

 1 const int maxn = 3000 + 10;
 2 double dp[55][maxn];
 3 
 4 class GraphWalkWithProbabilities {
 5 public:
 6     vector<int> win, lose;
 7     vector<int> g[55];
 8 
 9     double dfs(int node, int steps) {
10         double &res = dp[node][steps];
11         if(!(res < 0)) return res;
12         res = 0;
13         for(int to: g[node])
14             res = max(res, win[to]/100.0 + (100-win[to]-lose[to])/100.0*dfs(to, steps-1));
15         return res;
16     }
17     double findprob(vector <string> graph, vector <int> winprob, vector <int> loseprob, int Start) {
18         for(int i = 0; i < 55; i++) for(int j = 0; j < maxn; j++)
19             dp[i][j] = -1.0;
20 //        bug(1)
21         for(int i = 0; i < 55; i++) dp[i][0] = 0.0;
22         win = winprob;
23         lose = loseprob;
24 //        bug(1)
25         int n = sz(graph);
26         for(int i = 0; i < n; i++){
27             for(int j = 0; j < n; j++)
28                 if(graph[i][j] == '1')
29                 g[i].pb(j);
30         }
31         dfs(Start, maxn-1);
32         return dp[Start][maxn-1];
33     }
34 
35 
36 };
View Code

 div1

250pts  MaxMinTreeGame

题意:给定一棵N(2 <= N <= 50)的树,两人轮流进行游戏,每次可以删除一条边,然后选择保留其中一棵子树,直到仅剩下一个结点,游戏结束,每个结点都有一个权值,

A想要使得 最后结果尽量大,B想要使得结果尽量小,两人均按照最优方式进行,A先手,求A最终得到的最大值。

分析:所有度数为1的点的中权值最大值(M)即为结果,首先要证明所能获得的最大值不会超过M,因为N>=2的树中度数为1 的结点至少2个,

所以不论A先手时如何操作,剩下的树中,一定会保留下这些结点中的一个,B操作时选取即可,然后证明A先手能够保留权值最大的结点,这个是显然的。

代码:

 1 const int maxn = 55;
 2 int du[maxn];
 3 
 4 class MaxMinTreeGame {
 5     public:
 6     int findend(vector <int> edges, vector <int> costs) {
 7         memset(du, 0, sizeof du);
 8         int n = sz(edges) + 1;
 9         for(int i = 0; i < sz(edges); i++)
10             du[i+1]++, du[edges[i]]++;
11         int ans = 0;
12         for(int i = 0; i < n; i++)
13             if(du[i] == 1)
14             ans = max(ans, costs[i]);
15         return ans;
16     }
17 
18 
19 };
View Code

 

 

500pts PairsOfStrings

题意:给定字符集合为前k个小写字母,定义字符集合上的长度为n的A,B字符串,若存在定义在集合上的C使得A+C=C+B,那么(A,B)记为一对,

现在问(n,k)能够确定的数目,结果MOD (int)1e9 + 7。

分析:首先应该知道B应该是A旋转后的字符串,定义字符串的最小周期长度,A = d^n/d,表示A由n/d个长度为d字符串(记为s)链接构成,A = s + s + ... s,

且不存在更小的长度为d' < d的字符串s',s'重复n/d'之后能够得到A。这样A旋转操作能够得到的不同字符串就为d。那么对于本题需要知道最小周期长度的为d字符串有多少个(num),

最终结果就是所有的d*num之和。显然d应该是n的因子,可能的情况是k^d种,然后这里会有存在重复的情况,例如n = 8, d = 4时,结果k^4中,会包含d = 2中情况,

s = aaaa,A = s+s = aaaaaaaa,显然A可以看做周期长度更小的s' = aa,A = s' + s' + s' + s',所以要把d的因子d'所对应的情况排除。n <= (int)1e9,因子最多1300+个,最后复杂度应该是

O(1300*1300)。

代码:

 1 const int M = 1000000007;
 2 
 3 class PairsOfStrings {
 4 public:
 5     int num[1500];
 6     int powmod(LL a, LL b, LL c) {
 7         LL res = 1;
 8         while(b) {
 9             if(b&1) res = res*a%c;
10             a = a*a%c;
11             b >>= 1;
12         }
13         return res;
14     }
15     void addIt(int &x, int y) {
16         x = (x+y)%M;
17         if(x < 0) x += M;
18     }
19     void getDivisors(int n, vector<int> &div) {
20         div.clear();
21         int m = (int)sqrt(n+.5);
22         for(int i = 1; i <= m; i++)
23             if(n%i == 0) {
24                 div.pb(i);
25                 if(n/i != i)
26                     div.pb(n/i);
27             }
28         sort(div.begin(), div.end());
29     }
30     vector<int> div;
31     int getNumber(int n, int k) {
32 
33         getDivisors(n, div);
34         int ans = 0;
35         for(int i = 0; i < sz(div); i++) {
36             int x = div[i];
37             num[i] = powmod(k, x, M);
38             for(int j = 0; j < i; j++) {
39                 int y = div[j];
40                 if(x%y == 0) {
41                     addIt(num[i], -num[j]);
42                 }
43             }
44             addIt(ans, 1LL*num[i]*x%M);
45         }
46         return ans;
47     }
48 
49 
50 };
View Code

 

1000pts SumOfArrays

 题意:A,B两个数组长度 n <= 100000,A[i],B[i] < 100000,将A,B中的数排列后,使得C[i] = A[i]+B[i]使得C[i]中出现过的数Y出现次数最大。

分析:又是FFT的应用,做法很奇特!分别统计A[i]和B[i]中数出线次数即cntA[A[i]],cntB[B[i]],然后考虑

解法的关键之处就是这里的转化,考虑min(cntA[p],cntB[q]) >= k,那么C[p+q]为(p,q,k)的组数,针对k分别考虑:

k >= 10,显然cntA[p],cntB[q] >= k的p和去不超过(int)1e4,暴力统计C[p+q]的复杂度不会超过(int)1e8,当然实际复杂度可能更低。

k < 10,

z[] = full of zeros
For p = 0 ... 100000 {
    For each q = 0 ... 100000 {
        z[p + q] = z[p + q] + (x[p] * y[q])
    }
}
for i = 0 ... 200000 {
    C[i] = C[i] + z[i]
}
这里和大数的乘法十分相似,设立两个数组x[],y[],当x[p] = cntA[p] >= k,y[q] = cntB[q] >= k,剩下的部分利用FFT求出,z[p+q] += x[p]*y[q],由于FFT复杂度为O(MAX*log(MAX)),9次FFT是能够满足效率要求的。

代码:

  1 const int maxn = (int)2e5 + 10;
  2 const int LOW = 10;
  3 
  4 int cntA[maxn], cntB[maxn];
  5 int A[maxn], B[maxn], C[maxn];
  6 bitset<maxn> a, b;
  7 
  8 struct Complex {
  9     double x, y;
 10     Complex() {}
 11     Complex(double x, double y):x(x), y(y) {}
 12 };
 13 Complex operator + (const Complex &a, const Complex &b) {
 14     Complex c;
 15     c.x = a.x+b.x;
 16     c.y = a.y+b.y;
 17     return c;
 18 }
 19 Complex operator - (const Complex &a, const Complex &b) {
 20     Complex c;
 21     c.x = a.x-b.x;
 22     c.y = a.y-b.y;
 23     return c;
 24 }
 25 Complex operator * (const Complex &a, const Complex &b) {
 26     Complex c;
 27     c.x = a.x*b.x-a.y*b.y;
 28     c.y = a.x*b.y+a.y*b.x;
 29     return c;
 30 }
 31 
 32 inline void FFT(vector<Complex> &a, bool inverse) {
 33     int n = a.size();
 34     for(int i = 0, j = 0; i < n; i++) {
 35         if(j > i)
 36             swap(a[i], a[j]);
 37         int k = n;
 38         while(j & (k>>=1)) j &= ~k;
 39         j |= k;
 40     }
 41     double PI = inverse ? -pi : pi;
 42     for(int step = 2; step <= n; step <<= 1) {
 43         double alpha = 2*PI/step;
 44         Complex wn(cos(alpha), sin(alpha));
 45         for(int k = 0; k < n; k += step) {
 46             Complex w(1, 0);
 47             for(int Ek = k; Ek < k+step/2; Ek++) {
 48                 int Ok = Ek + step/2;
 49                 Complex u = a[Ek];
 50 
 51 
 52                 Complex t = a[Ok]*w;
 53                 a[Ok] = u-t;
 54                 a[Ek] = u+t;
 55                 w = w*wn;
 56             }
 57         }
 58     }
 59     if(inverse)
 60         for(int i = 0; i < n; i++)
 61             a[i].x = (a[i].x/n);
 62 }
 63 vector<int> operator * (const bitset<maxn> &v1, const bitset<maxn> &v2) {
 64     int S1 = v1.size(), S2 = v2.size();
 65     int S = 2;
 66     while(S < S1+S2) S <<= 1;
 67     vector<Complex> a(S), b(S);
 68     for(int i = 0; i < S; i++)
 69         a[i].x = a[i].y = b[i].x = b[i].y = 0.0;
 70     for(int i = 0; i < S1; i++)
 71         a[i].x = v1[i];
 72     for(int i = 0; i < S2; i++)
 73         b[i].x = v2[i];
 74     FFT(a, false);
 75     FFT(b, false);
 76     for(int i = 0; i < S; i++)
 77         a[i] = a[i] * b[i];
 78     FFT(a, true);
 79     vector<int> res(maxn, 0);
 80     for(int i = 0; i < maxn; i++)
 81         res[i] = round(a[i].x);
 82     return res;
 83 }
 84 
 85 class SumOfArrays {
 86 public:
 87     void gen(int A[], vector<int> seed, int n) {
 88         A[0] = seed[0];
 89         A[1] = seed[1];
 90         for(int i = 2; i < n; i++)
 91             A[i] = (1LL * A[i-1] * seed[2] + 1LL* A[i-2] * seed[3] + seed[4]) % seed[5];
 92 //        for(int i = 0; i < n; i++)
 93 //            printf("%d ", A[i]);
 94 //        puts("");
 95     }
 96     char ans[100];
 97 
 98     string findbestpair(int n, vector <int> Aseed, vector <int> Bseed) {
 99         gen(A, Aseed, n);
100         gen(B, Bseed, n);
101 //        memset(cntA, 0, sizeof cntA);
102         memset(cntB, 0, sizeof cntB);
103         memset(C, 0, sizeof C);
104 
105         for(int i = 0; i < n; i++) {
106             cntA[A[i]]++;
107             cntB[B[i]]++;
108         }
109 
110         vector<int> bigA, bigB;
111         for(int i = 0; i < maxn; i++) {
112             if(cntA[i] >= LOW)
113                 bigA.pb(i);
114             if(cntB[i] >= LOW)
115                 bigB.pb(i);
116         }
117 
118         for(int p: bigA) for(int q: bigB) {
119                 C[p+q] += min(cntA[p], cntB[q]) - LOW + 1;
120             }
121         vector<int> c(maxn);
122         for(int k = 1; k < 10; k++) {
123             a.reset();
124             b.reset();
125             for(int i = 0; i < maxn; i++) {
126                 if(cntA[i] >= k)
127                     a[i] = 1;
128                 if(cntB[i] >= k)
129                     b[i] = 1;
130             }
131 
132             c = a*b;
133             for(int i = 0; i < maxn; i++)
134                 C[i] += c[i];
135 //            for(int i = 1; i <= 4; i++)
136 //            cout << C[i] << ' ';
137 //            cout << endl;
138         }
139 
140         int X = -1, Y = 0;
141         for(int i = 0; i < maxn; i++)
142             if(C[i] >= X) {
143                 X = C[i];
144                 Y = i;
145             }
146 
147         sprintf(ans, "%d %d", X, Y);
148 //        TL
149         return ans;
150     }
151 
152 
153 };
View Code

 

posted on 2015-02-25 17:55  rootial  阅读(343)  评论(0编辑  收藏  举报

导航