VK Cup 2018 - Round 1+Codeforces Round #470

A. Primal Sport

  题意:有两个人轮流玩游戏。给出数X(i-1),轮到的人需要找到一个小于X(i-1)的素数x,然后得到Xi,Xi是x的倍数中大于等于X(i-1)的最小的数。现在已知X2,求最小的X0?

  思路:根据题意,X1的取值范围为【X1-X2的最大质因子+1,X2),同理可知X0的取值范围为【X1-X1的最大质因子+1,,X1)。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 using namespace std;
 6 const int maxn = 1000010;
 7 int Res[maxn],tmp[maxn];
 8 void Init()
 9 {
10     memset(tmp, -1, sizeof(tmp));
11     for (int i = 2; i < maxn; i++)
12     {
13         if (tmp[i] == -1)
14         {
15             for (int j = 2*i; j < maxn; j += i) tmp[j] = i;//标记质因子
16         }
17         if (tmp[i] == -1) Res[i] = i;//为质数
18         else Res[i] = i - tmp[i] + 1;//不是质数,tmp[i]为最大质因子
19     }
20 }
21 int main()
22 {
23     Init();
24     int n;
25     scanf("%d", &n);
26     int L = Res[n];
27     int ans = n;
28     for (int i = L; i < n; i++) ans = min(Res[i], ans);
29     printf("%d\n", ans);
30     return 0;
31 }
View Code

B. Producing Snow

  题意:有n天,每天都会产生Vi体积的雪花堆(堆与堆之间独立),每天存在的雪花都会融化Ti,问n天中各天融化的体积和。

  思路:用优先队列或最小堆维护,将Vi+sum(T1-Ti-1)加入队列或堆。堆中所有小于等于sum(T1-Ti)的都需要pop,当天融化的体积为所有pop出来的减去sum(Ti-Ti-1)加上还在堆里的数目*Ti.

堆实现:

 1 #include<iostream>
 2 #include<vector>
 3 #include<algorithm>
 4 #include<functional>
 5 using namespace std;
 6 const int maxn = 100010;
 7 int V[maxn],T[maxn];
 8 vector<long long>Heap;
 9 int main()
10 {
11     int n;
12     scanf("%d", &n);
13     make_heap(Heap.begin(), Heap.end(), greater<long long>());//建立最小堆
14     for (int i = 1; i <= n; i++) scanf("%d", V + i);
15     for (int i = 1; i <= n; i++) scanf("%d", T + i);
16     long long pre = 0;
17     for (int i = 1; i <= n; i++)
18     {
19         Heap.push_back(V[i]+pre);
20         push_heap(Heap.begin(), Heap.end(), greater<long long>());
21         long long tot = 0;
22         while (Heap.size()&&Heap[0] <= T[i]+pre)
23         {
24             tot += Heap[0]-pre;
25             pop_heap(Heap.begin(), Heap.end(), greater<long long>());
26             Heap.pop_back();
27         }
28         if (Heap.size())
29         {
30             tot += 1ll*T[i]*Heap.size();
31         }
32         if (i == n) printf("%I64d\n", tot);
33         else printf("%I64d ", tot);
34         pre += T[i];
35     }
36     return 0;
37 }
View Code

优先队列实现:

 1 #include<queue>
 2 #include<functional>
 3 #include<iostream>
 4 #include<cstdio>
 5 using namespace std;
 6 const int maxn = 100010;
 7 int V[maxn], T[maxn];
 8 
 9 int main()
10 {
11     priority_queue<long long, vector<long long>, greater<long long> >pq;
12     int n;
13     scanf("%d", &n);
14     for (int i = 1; i <= n; i++)
15     {
16         scanf("%d", V + i);
17     }
18     for (int i = 1; i <= n; i++)
19     {
20         scanf("%d", T + i);
21     }
22     long long pre = 0;
23     for (int i = 1; i <= n; i++)
24     {
25         pq.push(V[i] + pre);
26         long long tot = 0;
27         while (pq.size() && pq.top() <= pre + T[i])
28         {
29             tot += pq.top() - pre;
30             pq.pop();
31         }
32         tot += pq.size()*T[i];
33         pre += T[i];
34         if (i == n) printf("%I64d\n", tot);
35         else printf("%I64d ",tot);
36     }
37     return 0;
38 }
View Code

 C. Perfect Security

  题意:有n个数字构成的序列A,有一串n个数的key——P,求出key的某一个重新排序的序列,使得Ai^Pi最后得到的结果串字典序最小,并输出该结果串。

  思路:01异或字典树。注意插入的细节;查询时记得数目标记减1,因为P中每个数只能用一次。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cstdio>
 5 using namespace std;
 6 const int maxn = 300010;
 7 int A[maxn],P[maxn];
 8 const int bits = 32;
 9 const int SIZE = 2;
10 struct Trie
11 {
12     int Nums[maxn*bits][SIZE];
13     int ex[maxn*bits*SIZE];//经过结点i的数的数目
14     int Tot;
15 
16     void clear()
17     {
18         memset(Nums[0], 0, sizeof(Nums[0]));
19         Tot = 1;
20     }
21 
22     void insert(int Num)
23     {
24         int Now = 0, curchr;
25         for (int i = 29; i >=0; i--)
26         {
27             int c = ((Num>>i)&1);
28             if (!Nums[Now][c])
29             {
30                 memset(Nums[Tot], 0, sizeof(Nums[Tot]));
31                 ex[Tot] = 0;
32                 Nums[Now][c] = Tot++;
33             }
34             ex[Nums[Now][c]]++;//表示经过该点的数的数目
35             Now = Nums[Now][c];
36         }
37     }
38     int Search(int Num)
39     {
40         int u = 0,c;
41         for (int i = 29; i >=0; i--)
42         {
43             c =((Num>>i)&1);
44             if (ex[Nums[u][c]])
45             {
46                 u = Nums[u][c];
47                 ex[u]--;
48                 Num ^= (c << i);
49             }
50             else
51             {
52                 u = Nums[u][c^1];
53                 ex[u]--;
54                 Num ^= ((c ^ 1) << i);
55             }
56         }
57         return Num;
58     }
59 
60 }tree;
61 int main()
62 {
63     tree.clear();
64     int n;
65     scanf("%d", &n);
66     for (int i = 1; i <= n; i++)
67     {
68         scanf("%d", A + i);
69     }
70     for (int i = 1; i <= n; i++)
71     {
72         scanf("%d", P+i);
73     }
74     for (int i = 1; i <= n; i++) tree.insert(P[i]);
75     for (int i = 1; i <= n; i++)
76     {
77         int ans = tree.Search(A[i]);
78         if (i == n) printf("%d\n", ans);
79         else printf("%d ", ans);
80     }
81     return 0;
82 }
View Code

 D. Picking Strings

  题意:给出S原串和T原串,每次各选取一个子区间,问在题目的变换下:A->BC,B->AC,C->AB,AAA->empty,是否能够从S串变换到T串?

  思路:

B->AC->AAB->AAAC->C;C->AB->AAC->AAAB->B(B和C等价,可以将所有C替换为B)
AB->AAC->AAAB->B;B->AC->AB(B前面的A可以任意增减)
A->BC->BB(A可以转换为BB)
B->AB->BBB(已有B时,B的数量增加任意偶数个)
故只需考虑子串末尾A。由于末尾A无法被转化成,故原串和目标串末尾A数目需要保留相同个数
1.当T串B少,无解(B无法消除,只能增加)
2.当两串B数目奇偶数不同,无解(B只能增加偶数个)
3.T串末尾A比S串多,无解(末尾A无法增加,只能减少)
否则(两串B数目奇偶相同):
4.T串B多,S串末尾A多,必有解
5.两串B相同,S串末尾A比T串多的数目为3的倍数时有有解
6.两串A相同,S串有B即可。
7.其他无解

 1 //B->AC->AAB->AAAC->C;C->AB->AAC->AAAB->B(B和C等价,可以将所有C替换为B)
 2 //AB->AAC->AAAB->B;B->AC->AB(B前面的A可以任意增减)
 3 //A->BC->BB(A可以转换为BB)
 4 //B->AB->BBB(已有B时,B的数量增加任意偶数个)
 5 //故只需考虑子串末尾A。由于末尾A无法被转化成,故原串和目标串末尾A数目需要保留相同个数
 6 //1.当T串B少,无解(B无法消除,只能增加)
 7 //2.当两串B数目奇偶数不同,无解(B只能增加偶数个)
 8 //3.T串末尾A比S串多,无解(末尾A无法增加,只能减少)
 9 //否则(两串B数目奇偶相同):
10 //4.T串B多,S串末尾A多,必有解
11 //5.两串B相同,S串末尾A比T串多的数目为3的倍数时有有解
12 //6.两串A相同,S串有B即可。
13 //7.其他无解
14 #include<iostream>
15 #include<algorithm>
16 #include<cstring>
17 #include<cstdio>
18 using namespace std;
19 const int maxn = 100010;
20 char S[maxn], T[maxn];
21 //记录前i个字符中B+C的前缀和;记录以i结尾的连续A的个数
22 int Sa[maxn], Sb[maxn];
23 int Ta[maxn], Tb[maxn];
24 int main()
25 {
26     int n;
27     scanf("%s%s%d", S+1, T+1,&n);
28     int len1 = strlen(S+1), len2 = strlen(T+1);
29     for (int i = 1; i <= len1; i++)
30     {
31         if (S[i] == 'A') Sa[i] = Sa[i - 1] + 1;
32         Sb[i] = (S[i] == 'A') ? Sb[i - 1] : Sb[i - 1] + 1;
33     }
34     for (int i = 1; i <= len2; i++)
35     {
36         if (T[i] == 'A') Ta[i] = Ta[i - 1] + 1;
37         Tb[i] = (T[i] == 'A') ? Tb[i - 1] : Tb[i - 1] + 1;
38     }
39     while (n--)
40     {
41         int a, b, c, d;
42         scanf("%d%d%d%d", &a, &b, &c, &d);
43         int len1 = b - a + 1, len2 = d - c + 1;
44         int t_sa = min(len1, Sa[b]), t_sb = Sb[b] - Sb[a - 1];
45         int t_ta = min(len2, Ta[d]), t_tb = Tb[d] - Tb[c - 1];
46         //当T串B少,当两串B数目奇偶数不同,T串末尾A比S串多,无解
47         if (t_sb > t_tb || (t_sb % 2) != (t_tb % 2) || t_ta > t_sa) printf("0");
48         else if(t_tb>t_sb&&t_sa>t_ta)//隐含两串B数目奇偶相同
49         {//T串B多,S串A多(多出的A可以转化为BB,前面非连续的A始终可以转化)
50             printf("1");
51         }
52         else if (t_tb == t_sb)
53         {//此时只有Sa-Ta多出的a的数目为3的倍数才能转化
54             if ((t_sa - t_ta) % 3 == 0) printf("1");
55             else printf("0");
56         }
57         else if (t_ta == t_sa)
58         {//此时只要sb的数目大于0
59             if (t_sb) printf("1");
60             else printf("0");
61         }
62         else printf("0");
63     }
64     printf("\n");
65     return 0;
66 }
View Code

 A2. Protect Sheep

  题意:有一个牧场,‘S’为羊,现在需要放置‘D’狗,防止羊‘S’被狼‘W’通过上下左右吃到。任意一种方案即可,放置狗的数目不限

  思路:简单DFS

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 using namespace std;
 5 const int maxn = 510;
 6 char MP[maxn][maxn];
 7 bool Find[maxn][maxn];
 8 int dx[] = { 0,0,1,-1 };
 9 int dy[] = { 1,-1,0,0 };
10 int R, C;
11 bool flag;
12 void DFS(int ux,int uy)
13 {
14     for (int i = 0; i < 4; i++)
15     {
16         if (!flag) return;
17         int tx = ux + dx[i], ty = uy + dy[i];
18         if (tx >= R || tx < 0 || ty >= C || ty < 0) continue;
19         if (MP[tx][ty] == 'W')
20         {
21             flag = false;
22             return;
23         }
24         else if (MP[tx][ty] == 'S'&&!Find[tx][ty])
25         {
26             Find[tx][ty] = true;
27             DFS(tx, ty);
28         }
29         else if (MP[tx][ty] == '.') MP[tx][ty] = 'D';
30     }
31 }
32 int main()
33 {
34     scanf("%d%d", &R, &C);
35     flag = true;
36     for (int i = 0; i < R; i++) scanf("%s", MP + i);
37     for (int i = 0; i < R; i++)
38     {
39         for (int j = 0; j < C; j++)
40         {
41             if (MP[i][j] == 'S' && !Find[i][j])
42             {
43                 Find[i][j] = true;
44                 DFS(i, j);
45             }
46         }
47     }
48     if (flag)
49     {
50         printf("Yes\n");
51         for (int i = 0; i < R; i++) printf("%s\n", MP + i);
52     }
53     else printf("No\n");
54     return 0;
55 }
View Code

 

posted @ 2018-03-13 14:22  萌萌的美男子  阅读(322)  评论(0编辑  收藏  举报