• 2017-2018 ACM-ICPC Southeastern European Regional Programming Contest (SEERC 2017) Solution


    A:Concerts

    题意:给出一个串T, 一个串S,求串S中有多少个串T,可以重复,但是两个字符间的距离要满足给出的数据要求

    思路:先顺序统计第一个T中的字符在S中有多少个,然后对于第二位的以及后面的,我们从后面往前推,前缀和搞一搞,注意间距

     1 #include<bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 #define N 100010
     6 
     7 typedef long long ll;
     8 
     9 const int MOD = 1e9 + 7;
    10 
    11 ll sum[N];
    12 
    13 char strN[N], strK[N];
    14 
    15 int n,k;
    16 int pos[100];
    17 
    18 int main()
    19 {
    20     while(~scanf("%d %d",&k,&n))
    21     {
    22         memset(sum, 0, sizeof sum);
    23         for(int i = 0; i < 26; ++i)
    24         {
    25             scanf("%d",&pos[i]);
    26         }
    27         scanf("%s",strK + 1);
    28         scanf("%s",strN + 1);
    29         for(int i = 1;i <= n; ++i)
    30         {
    31             sum[i] = (strN[i] == strK[1]) + sum[i - 1];
    32             sum[i] %= MOD;
    33         }
    34         for(int i = 2; i <= k; ++i)
    35         {
    36             for(int j = n; j >= 1; --j)
    37             {
    38                 if(strN[j] == strK[i])
    39                 {
    40                     int idx = strK[i - 1] - 'A';
    41                     idx = pos[idx];
    42                     if(j - idx - 1 < 1) sum[j] = 0;
    43                     else sum[j] = sum[j - idx - 1];
    44                 }
    45                 else sum[j] = 0;
    46             }
    47             for(int j = 1;j <= n; ++j)
    48             {
    49                 sum[j] += sum[j - 1];
    50                 sum[j] %= MOD;
    51             }
    52         }
    53         printf("%lld
    ",sum[n]);
    54     }
    55     return 0;
    56 }
    View Code

    B:Bricks

    留坑。

    C:Christmas Tree

    留坑。

    D:Harry Potter and The Vector Spell

    题意:给出n个向量,每个向量有m维,n个向量中有且只有两维上是一,然后重载了加号运算符和乘号运算符,求最多的非线性相关的向量个数

    思路:因为每个向量中有且只有两个1,那么可以想象答案最大肯定是m - 1 因为分布肯定是这样的

    那么我们考虑将每个向量的两个1连一条边,那么每个连通块对答案的贡献就是 连通块里面的点数减1

     1 #pragma comment(linker, "/STACK:1024000000,1024000000") 
     2 
     3 #include <bits/stdc++.h>
     4 using namespace std;
     5 
     6 #define INF 0x3f3f3f3f
     7 #define INFLL 0x3f3f3f3f3f3f3f3f
     8 #define ll long long 
     9 #define N 100100
    10 
    11 int m, n;
    12 int pre[N];
    13 int arr[N];
    14 
    15 inline int find(int x)
    16 {
    17     if (x != pre[x])
    18         pre[x] = find(pre[x]);
    19     return pre[x];
    20 }
    21 
    22 inline void join(int x, int y)
    23 {
    24     int fx = find(x), fy = find(y);
    25     if (fx != fy)
    26         pre[fx] = fy;
    27 }
    28 
    29 inline void Run()
    30 {
    31     while (scanf("%d%d", &m, &n) != EOF)
    32     {
    33         memset(arr, 0, sizeof arr);
    34         for (int i = 1; i <= m; ++i)
    35             pre[i] = i;
    36         for (int i = 1, tot, x; i <= m; ++i)
    37         {
    38             scanf("%d", &tot);
    39             while (tot--)
    40             {
    41                 scanf("%d", &x);
    42                 if (arr[x])
    43                     join(arr[x], i);
    44                 else
    45                     arr[x] = i;
    46             }
    47         }
    48         int cnt = 0;
    49         for (int i = 1; i <= m; ++i)
    50             if (pre[i] == i) ++cnt;
    51         printf("%d
    ", m - cnt);
    52     }
    53 }
    54 
    55 int main()
    56 {
    57     #ifdef LOCAL
    58         freopen("Test.in", "r", stdin);
    59     #endif
    60 
    61     Run();
    62     
    63     return 0;
    64 }
    View Code

    E:Looping Playlist

    留坑。

    F:Binary Transformations

    题意:给出两个01串,每位有一个权值,然后要从a串变成b串,每换一次的花费是变之后a串中里面每一位是1的对应的权值和,求最小花费

    思路:贪心的想法

    先把1变成0,按权值大小从大到小变,把0变成1,按权值从小到大变

    存在一个问题,如果本来a对应的那位以及b对应的那位都是1,但是那位权值特别特别大,可以将它先变成0,最后再变回来,可能会使得花费更少

    容易知道,如果将a里面所有为1位的权值从大到小排序,那么如果存在这样的方案使得花费减少,那么肯定是一段连续的,枚举长度,

    时间复杂度O(n ^ 2)

    注意随手剪枝

      1 #include<bits/stdc++.h>
      2 
      3 using namespace std;
      4 
      5 typedef long long ll;
      6 #define N 5010
      7 const ll INFLL = 0x3f3f3f3f3f3f3f3f;
      8 struct node{
      9     int pos;
     10     int cost;
     11     inline node(){}
     12     inline node(int pos,int cost) :pos(pos), cost(cost){}
     13     inline bool operator < (const node &b) const
     14     {
     15         return cost > b.cost;
     16     }
     17 };
     18 
     19 inline bool cmp1(node a, node b)
     20 {
     21     return a.cost > b.cost;
     22 }
     23 
     24 inline bool cmp2(node a, node b)
     25 {
     26     return a.cost < b.cost;
     27 }
     28 
     29 int n;
     30 ll sum;
     31 int cost[N];
     32 char s1[N];
     33 char s2[N];
     34 
     35 int main()
     36 {
     37     while(~scanf("%d",&n))
     38     {
     39         for(int i = 1; i <= n; ++i)
     40         {
     41             scanf("%d", &cost[i]);
     42         }
     43         sum = 0;
     44         scanf("%s", s1 + 1);
     45         scanf("%s", s2 + 1);
     46         vector<node>ONE, ZERO_ONE;
     47         for(int i = 1; i <= n; ++i)
     48         {
     49             if(s1[i] == '1')
     50             {
     51                 ONE.push_back(node(i, cost[i]));
     52                 sum += cost[i];
     53             }
     54             else if(s1[i] == '0' && s2[i] == '1')
     55             {
     56                 ZERO_ONE.push_back(node(i, cost[i]));
     57             }
     58         }
     59         sort(ONE.begin(), ONE.end(), cmp1);
     60         int len = ONE.size();
     61         ll Begin = sum;
     62         ll ans = INFLL;
     63         for(int sz = -1; sz < len; ++sz)
     64         {
     65             ll tmp = 0;
     66             sum = Begin;
     67             for(int i = 0; i <= sz; ++i)
     68             {
     69                 sum -= ONE[i].cost;
     70                 tmp += sum;
     71                 if(tmp >= ans) break;
     72             }
     73             if(tmp >= ans) continue;
     74             for(int i = sz + 1; i < len; ++i)
     75             {
     76                 int p = ONE[i].pos;
     77                 if(s2[p] == '0')
     78                 {
     79                     sum -= ONE[i].cost;
     80                     tmp += sum;
     81                     if(tmp >= ans) break;
     82                 }
     83             }
     84             if(tmp >= ans) continue;
     85             vector<node>CHANGE = ZERO_ONE;
     86             for(int i = 0; i <= sz; ++i)
     87             {
     88                 int p = ONE[i].pos;
     89                 if(s1[p] == '1' && s2[p] == '1')
     90                 {
     91                     CHANGE.push_back(node(p, cost[p]));
     92                 }
     93             }
     94             sort(CHANGE.begin(), CHANGE.end(), cmp2);
     95             for(int i = 0, lenn = CHANGE.size(); i < lenn; ++i)
     96             {
     97                 sum += CHANGE[i].cost;
     98                 tmp += sum;
     99                 if(tmp >= ans) break;
    100             }
    101             ans = min(ans, tmp);
    102         }
    103         printf("%lld
    ",ans);
    104     }
    105     return 0;
    106 }
    View Code

    G:Robots

    题意:给出n组数据,每组数据包含一个加速度和时间,求按顺序得到的距离,以及按最优顺序得到距离的不同

    思路:先遍历一遍算一下,然后贪心按加速度排一下,算一下,算差距

     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 #define N 10010
     6 
     7 struct node
     8 {
     9     double a, s;
    10     inline void scan()
    11     {
    12         scanf("%lf%lf", &a, &s);
    13     }
    14     inline bool operator < (const node &r) const
    15     {
    16         return a  > r.a;
    17     }
    18 }arr[N];
    19 
    20 int n;
    21 
    22 inline double work()
    23 {
    24     double res = 0;
    25     double v = 0;
    26     for (int i = 1; i <= n; ++i)
    27     {
    28         double t = arr[i].s;
    29         res += v * t + arr[i].a * t * t / 2;
    30         v += arr[i].a * t;
    31     }
    32     return res;
    33 }
    34 
    35 int main()
    36 {
    37     while (scanf("%d", &n) != EOF)
    38     {
    39         for (int i = 1; i <= n; ++i) arr[i].scan();
    40         double sum1 = work();
    41         sort(arr + 1, arr + 1 + n);
    42         double sum2 = work();
    43 //        printf("%lf %lf
    ", sum1, sum2);
    44         printf("%.1f
    ", sum2 - sum1);
    45     }
    46     return 0;
    47 }
    View Code

    H:Cat and Mouse

    留坑。

    I:Tetris

    留坑。

    J:Cunning Friends

    题意:有n堆石头,第i堆有ai个,A先取,每次从一堆中取的数量不等于0,然后B 和 C取 谁不能取了谁就输了,B 和 C 想让A输,假设每个人的决策都是最佳的,求A是必败还是必输

    思路:可以考虑一下几种情况

    1° 全是1的情况  那么用n%3 看一下余数,如果余数是0 那么A是必输的

    2°只有一个不是1的情况,那么A是必胜的,因为假如堆数%3 == 0 那么 我将不是1的那堆取成1,这样就相当于变成了堆数%3==1 变成必胜态

    3°有两个不是1的情况

    首先我们可以知道,假如只有两堆,并且这两堆都不是1,那么A是必输的

    那转化成加了若干堆1,那么这若干堆1当中如果%3 == 0 那么A是必输的

    如果不是,并且存在至少一堆是2,A是赢的

    4° 其他情况都是必输的

     1 #pragma comment(linker, "/STACK:1024000000,1024000000") 
     2 
     3 #include <cstdio>
     4 #include <cmath>
     5 #include <algorithm>
     6 #include <iostream>
     7 
     8 using namespace std;
     9 
    10 #define INF 0x3f3f3f3f
    11 #define INFLL 0x3f3f3f3f3f3f3f3f
    12 #define ll long long 
    13 #define N 100100
    14 
    15 int n;
    16 
    17 int ONE, TWO;
    18 
    19 inline bool work()
    20 {
    21     if (ONE == n - 1) return true;
    22     else if (ONE == n)
    23         return n % 3;
    24     if (ONE == n - 2)
    25     {
    26         if (n % 3 == 2) return false;
    27         if (TWO) return true;
    28         return false;
    29     }
    30     return false;
    31 }
    32 
    33 inline void Run()
    34 {
    35     while (scanf("%d", &n) != EOF)
    36     {
    37         ONE = 0, TWO = 0;
    38         for (int i = 1, num; i <= n; ++i)
    39         {
    40             scanf("%d", &num);
    41             if (num == 1) ++ONE;
    42             if (num == 2) ++TWO;
    43         }
    44         puts(work() ? "Win" : "Lose");
    45     }
    46 }
    47 
    48 int main()
    49 {
    50     #ifdef LOCAL
    51         freopen("Test.in", "r", stdin);
    52     #endif
    53 
    54     Run();
    55     
    56     return 0;
    57 }
    View Code

    k:Escape Room

    题意:有一个长度为n的序列,里面的数是1 - n 然后给出每一位以当前位为队头的最长上升子序列长度,还原原序列,多个答案输出字典序最小的那个

    思路:

    比如说 1 2 2 1

    我们可以考虑先放长度为1 的

    肯定是从后面取两个数 放 4 和 3

    然后 长度就变成

    0 1 1 0

    然后又取两个 2 1 放下去

     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 #define N 10010
     6 
     7 struct node
     8 {
     9     double a, s;
    10     inline void scan()
    11     {
    12         scanf("%lf%lf", &a, &s);
    13     }
    14     inline bool operator < (const node &r) const
    15     {
    16         return a  > r.a;
    17     }
    18 }arr[N];
    19 
    20 int n;
    21 
    22 inline double work()
    23 {
    24     double res = 0;
    25     double v = 0;
    26     for (int i = 1; i <= n; ++i)
    27     {
    28         double t = arr[i].s;
    29         res += v * t + arr[i].a * t * t / 2;
    30         v += arr[i].a * t;
    31     }
    32     return res;
    33 }
    34 
    35 int main()
    36 {
    37     while (scanf("%d", &n) != EOF)
    38     {
    39         for (int i = 1; i <= n; ++i) arr[i].scan();
    40         double sum1 = work();
    41         sort(arr + 1, arr + 1 + n);
    42         double sum2 = work();
    43 //        printf("%lf %lf
    ", sum1, sum2);
    44         printf("%.1f
    ", sum2 - sum1);
    45     }
    46     return 0;
    47 }
    View Code

    L:Divide and Conquer

    留坑。

  • 相关阅读:
    c语言中srand和rand函数 生成随机数总结
    枚举类型
    VS2008快捷键使用技巧
    PV实现同步
    PV操作(深入显出)
    数字在排序数组中出现的次数
    两个链表的第一个公共结点
    数组中的逆序对
    第一个只出现一次的字符位置
    丑数
  • 原文地址:https://www.cnblogs.com/Dup4/p/9497946.html
Copyright © 2020-2023  润新知