• 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
  • 相关阅读:
    如何高效学习读书笔记
    对Java虚拟机理解
    对Java虚拟机的认识和理解
    翻译一篇关于jedis的文章
    Java 异常机制
    spring boot基础 入门
    每天记录一个设计模式之建造者模式
    如何在mybatis 中使用In操作
    Git 基本命令有哪些
    JavaScript
  • 原文地址:https://www.cnblogs.com/rootial/p/4299724.html
Copyright © 2020-2023  润新知