• CodeForces Round #286 Div.2


    A. Mr. Kitayuta's Gift (枚举)

    题意:

    给一个长度不超过10的串,问能否通过插入一个字符使得新串成为回文串。

    分析:

    因为所给的串很多,所以可以枚举 “在哪插入” 和 “插入什么”,写一个二重循环枚举新串,判断是否为回文串。时间复杂度为O(n3)

    还可只枚举插入位置(在那个位置用一个特殊字符表示),在判断的时候,如果遇到特殊字符,则所插入的字符一定为镜像的字符。

     1 #include <cstdio>
     2 #include <cstring>
     3 
     4 char s[15], s1[15];
     5 int l;
     6 
     7 bool judge()
     8 {
     9     for(int i = 0; i < (l+1)/2; ++i)
    10         if(s1[i] == 0) s1[i] = s1[l-i];
    11         else if(s1[l-i] == 0) s1[l-i] = s[i];
    12         else if(s1[i] != s1[l-i]) return false;
    13 
    14     return true;
    15 }
    16 
    17 int main()
    18 {
    19     scanf("%s", s);
    20     l = strlen(s);
    21     bool flag = false;
    22     for(int pos = 0; pos <= l; ++pos)
    23     {//枚举所加入字符的位置,s1为得到的新串
    24         int i;
    25         for(i = 0; i < pos; ++i) s1[i] = s[i];
    26         s1[i++] = 0;
    27         for(; i <= l; ++i)s1[i] = s[i-1];
    28         if(judge()) { flag = true; break; }
    29     }
    30 
    31     if(!flag) puts("NA");
    32     else
    33     {
    34         for(int i = 0; i <= l; ++i)
    35             if(s1[i] == 0) printf("a");
    36             else printf("%c", s1[i]);
    37     }
    38 
    39     return 0;
    40 }
    代码君

    B. Mr. Kitayuta's Colorful Graph (并查集)

    题意:

    有一个多种颜色的无向图,给出每条边的两个顶点以及该边的颜色。

    然后有若干次询问,每次询问两点间共有多少种颜色的通路。

    分析:

    这道题可以理解为二维的并查集。如果没有颜色的区分,可以判断两点是否连通。

    现在给边染上颜色,则我们可以分开处理。最后在询问的时候枚举所有颜色,判断两点是否连通。

     1 #include <cstdio>
     2 #include <vector>
     3 #include <cstring>
     4 #include <algorithm>
     5 using namespace std;
     6 
     7 const int maxn = 100  + 10;
     8 
     9 int G[maxn][maxn];
    10 int n, m;
    11 int p[maxn][maxn];
    12 //找颜色为color的边中,x的父节点
    13 int findp(int color, int x) { return x == p[color][x] ? x : p[color][x] = findp(color, p[color][x]); }
    14 
    15 struct Edge
    16 {
    17     int u, v;
    18     Edge(int u=0, int v=0):u(u), v(v) {}
    19 };
    20 
    21 vector<Edge> edges[maxn];
    22 
    23 int main()
    24 {
    25     //freopen("in.txt", "r", stdin);
    26     int n, m, Mc = 0;
    27     scanf("%d%d", &n, &m);
    28     //并查集初始化
    29     for(int i = 1; i <= m; ++i)
    30         for(int j = 1; j <= n; ++j)
    31             p[i][j] = j;
    32 
    33     for(int i = 0; i < m; ++i)
    34     {
    35         int a, b, c;
    36         scanf("%d%d%d", &a, &b, &c);
    37         Mc = max(Mc, c);
    38         int pa = findp(c, a);
    39         int pb = findp(c, b);
    40         if(pa != pb) p[c][pa] = pb;
    41     }
    42 
    43     int Q;
    44     scanf("%d", &Q);
    45     for(int i = 0; i < Q; ++i)
    46     {
    47         int u, v, cnt = 0;
    48         scanf("%d%d", &u, &v);
    49         for(int c = 1; c <= Mc; ++c) //枚举所有颜色
    50             if(findp(c, u) == findp(c, v))
    51                 cnt++;
    52         printf("%d
    ", cnt);
    53     }
    54 
    55     return 0;
    56 }
    代码君

    C. Mr. Kitayuta, the Treasure Hunter (DP)

    题意:

    参见原文吧,=_=||

    Mr. Kitayuta, the Treasure Hunter

    分析:

    设dp(i, j)表示跳到第i个岛步长为j,wi表示第i个岛的宝石数,最大能取到的宝石数。

    状态转移方程为 dp(i, j) = wi + max{dp(i+j-1, j-1), dp(i+j, j), dp(i+j+1, j+1)}

    上式是从后往前推的,最终答案是dp(d, d)。

    从前往后推也是一样的,不过要维护一个最大值。

    还有一个很严重的问题就是:30000×30000的空间太大了!

    再深入分析,其实步长的变化范围没有3w那么大。

    假设每一步步长为前面步长加一,可以求出最大步长。类似地,求出最小步长。

    假设d=1,最大步长不会超过245 + d,因为

    同样的,如果d≤244,则最小步长为0.

    如果d≥245,

    所以,最小步长不会小于max{0, d - 245}.

     1 #include <cstdio>
     2 #include <algorithm>
     3 using namespace std;
     4 
     5 int max3(int a, int b, int c)
     6 { return max(max(a, b), c); }
     7 
     8 int w[70000], dp[65000][500];
     9 
    10 int main()
    11 {
    12     //freopen("in.txt", "r", stdin);
    13 
    14     int n, d;
    15     scanf("%d%d", &n, &d);
    16     for(int i = 0; i < n; ++i)
    17     {
    18         int x;
    19         scanf("%d", &x);
    20         w[x]++;
    21     }
    22 
    23     int maxp, minp = 1;
    24     for(int n = 0; ; n++) if(d*(n+1)+n*(n+1)/2 >= 30000)
    25     {
    26         maxp = d + n;   //最大步长
    27         break;
    28     }
    29     for(int n = 0; d >= 245; n++) if(d*(n+1)-n*(n+1)/2 >= 30000)
    30     {
    31         minp = d - n;   //最小步长
    32         break;
    33     }
    34 
    35     for(int x = 30000; x >= d; --x)
    36         for(int l = minp; l <= maxp; ++l)
    37             dp[x][l-minp+1] = w[x] + max3(dp[x+l][l-minp+1], dp[x+l+1][l+2-minp], dp[x+l-1][l-minp]);
    38 
    39     printf("%d
    ", dp[d][d+1-minp]);
    40 
    41     return 0;
    42 }
    代码君
  • 相关阅读:
    网络爬虫工具
    Redmine
    数据挖掘算法Analysis Services-基于SQL Server的数据挖掘
    数据挖掘和互联网广告-如何应对网盟广告作弊

    支付宝VIE的罪与罚
    迭代
    App如何推广秘籍之”渠道为王”
    Introducing Holographic Emulation
    Resources.Load加载文件返回null的原因
  • 原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/4248074.html
Copyright © 2020-2023  润新知