Codeforces Round #302 解题报告

  感觉今天早上虽然没有睡醒但是效率还是挺高的...

  Pas和C++换着写...



  

544A. Set of Strings

You are given a string q. A sequence of k strings s1, s2, ..., sk is called beautiful, if the concatenation of these strings is string q(formally, s1 + s2 + ... + sk = q) and the first characters of these strings are distinct.

Find any beautiful sequence of strings or determine that the beautiful sequence doesn‘t exist.

  每个在之前没有出现过的字母作一个标记,作为每个字符串的开头

  如果数量不足则输出-1

 1 var i,k,j:longint;
 2     vis:array[‘a‘..‘z‘]of boolean;
 3     v:array[-1..110]of boolean;
 4     s:ansistring;
 5
 6 begin
 7     readln(k);
 8     readln(s);
 9     fillchar(vis,sizeof(vis),true);
10         fillchar(v,sizeof(v),true);
11     for i:=1 to length(s) do if vis[s[i]] then
12     begin
13         vis[s[i]]:=false;v[i]:=false;dec(k);
14         if k=0 then break;
15     end;
16     if k>0 then writeln(‘NO‘) else
17     begin
18         writeln(‘YES‘);
19         i:=1;
20         while i<=length(s) do
21         begin
22             write(s[i]);
23             j:=i+1;
24             while (j<=length(s))and(v[j]) do
25             begin
26                 write(s[j]);
27                 inc(j);
28             end;
29             writeln;
30             i:=j;
31         end;
32     end;
33 end.

544B. Sea and Islands

A map of some object is a rectangular field consisting of n rows and n columns. Each cell is initially occupied by the sea but you can cover some some cells of the map with sand so that exactly k islands appear on the map. We will call a set of sand cells to be island if it is possible to get from each of them to each of them by moving only through sand cells and by moving from a cell only to a side-adjacent cell. The cells are called to be side-adjacent if they share a vertical or horizontal side. It is easy to see that islands do not share cells (otherwise they together form a bigger island).

Find a way to cover some cells with sand so that exactly k islands appear on the n × n map, or determine that no such way exists.

  又是一道看样例就会思路乱掉的题..

  非常简单,每个小岛占一格就好了..

  直接按照横纵坐标和差的奇偶性判断是否放沙

 1 var i,j,n,k:longint;
 2 begin
 3     readln(n,k);
 4     if k>(n*n+1) >> 1 then writeln(‘NO‘) else
 5     begin
 6         writeln(‘YES‘);
 7         for i:=1 to n do
 8         begin
 9             for j:=1 to n do if ((i+j) and 1=0)and(k>0) then
10             begin
11                 write(‘L‘);dec(k);
12             end else write(‘S‘);
13             writeln;
14         end;
15     end;
16 end.

543A. Writing Code

Programmers working on a large project have just received a task to write exactly m lines of code. There are n programmers working on a project, the i-th of them makes exactly ai bugs in every line of code that he writes.

Let‘s call a sequence of non-negative integers v1, v2, ..., vn a plan, if v1 + v2 + ... + vn = m. The programmers follow the plan like that: in the beginning the first programmer writes the first v1 lines of the given task, then the second programmer writes v2 more lines of the given task, and so on. In the end, the last programmer writes the remaining lines of the code. Let‘s call a plan good, if all the written lines of the task contain at most b bugs in total.

Your task is to determine how many distinct good plans are there. As the number of plans can be large, print the remainder of this number modulo given positive integer mod.

  感觉比赛的时候脑子坏掉了...

  一直觉得要枚举一个数量所以n^4...甚至想要去写二进制背包这种两年没写过的东西...

  然而不确定数量的背包直接正序就好了啊...

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 int a[510],f[510][510];
 5 int main(){
 6     int n,m,b,tt;
 7     scanf("%d%d%d%d",&n,&m,&b,&tt);
 8     for (int i=1;i<=n;i++) scanf("%d",&a[i]);
 9     f[0][0] = 1;
10     for (int i=1;i<=n;i++)
11         for (int j=1;j<=m;j++)
12             for (int k=a[i];k<=b;k++) f[j][k]=(f[j][k]+f[j-1][k-a[i]])%tt;
13     int ans=0;
14     for (int i=0;i<=b;i++) ans=(ans+f[m][i])%tt;
15     printf("%d\n",ans);
16     return 0;
17 }

543B. Destroying Roads

In some country there are exactly n cities and m bidirectional roads connecting the cities. Cities are numbered with integers from 1 to n. If cities a and b are connected by a road, then in an hour you can go along this road either from city a to city b, or from city b to city a. The road network is such that from any city you can get to any other one by moving along the roads.

You want to destroy the largest possible number of roads in the country so that the remaining roads would allow you to get from city s1to city t1 in at most l1 hours and get from city s2 to city t2 in at most l2 hours.

Determine what maximum number of roads you need to destroy in order to meet the condition of your plan. If it is impossible to reach the desired result, print -1.

  好多叉点的题...

  首先为了使总路程最短...肯定首先想到分别求最短路...

  然而还有一种方法,就是让两条路径重合,可以证明得到,重合的部分一定是连续的一段

  因为如果有多段的话,中间分开的部分合在一起一定是一个更优的解

  所以可以用n次bfs求出多源最短路

  将上面几种方法尝试一下然后更新出答案

  然而还要注意两个点分别连接的不一定都是起点或都是终点,要讨论一下...

 1 const maxn = 3010;maxm=200010;INF=100000007;
 2 var fa,next:array[-1..maxm]of longint;
 3     link,opt:array[-1..maxn]of longint;
 4     vis:array[-1..maxn]of boolean;
 5     dis:array[-1..maxn,-1..maxn]of longint;
 6     ans,s1,t1,h1,s2,t2,h2,n,m,e,i,x,y,j:longint;
 7
 8 procedure add(x,y:longint);
 9 begin
10     inc(e);fa[e]:=y;next[e]:=link[x];link[x]:=e;
11     inc(e);fa[e]:=x;next[e]:=link[y];link[y]:=e;
12 end;
13
14 function min(a,b:longint):longint;
15 begin
16     if a<b then exit(a) else exit(b);
17 end;
18
19 function max(a,b:longint):longint;
20 begin
21     if a>b then exit(a) else exit(b);
22 end;
23
24 procedure bfs(s:longint);
25 var head,tail,x,j,i:longint;
26 begin
27     for i:=1 to n do dis[i,s]:=INF;
28     fillchar(vis,sizeof(vis),true);
29     head:=0;tail:=1;dis[s,s]:=0;vis[s]:=false;opt[1]:=s;
30     while head<>tail do
31     begin
32         inc(head);
33         x:=opt[head];j:=link[x];
34         while j<>0 do
35         begin
36             if vis[fa[j]] then
37             begin
38                 vis[fa[j]]:=false;
39                 dis[fa[j],s]:=dis[x,s]+1;
40                 inc(tail);opt[tail]:=fa[j];
41             end;
42             j:=next[j];
43         end;
44     end;
45 end;
46
47 begin
48     readln(n,m);
49     e:=0;
50     for i:=1 to m do
51     begin
52         readln(x,y);add(x,y);
53     end;
54     for i:=1 to n do bfs(i);
55     readln(s1,t1,h1);readln(s2,t2,h2);
56     ans:=-1;
57     if (dis[s1,t1]<=h1)and(dis[s2,t2]<=h2) then ans:=max(ans,max(0,m-dis[s1,t1]-dis[s2,t2]));
58     for i:=1 to n do
59         for j:=1 to n do
60         begin
61             if (dis[i,s1]+dis[i,j]+dis[j,t1]<=h1)and(dis[i,s2]+dis[i,j]+dis[j,t2]<=h2) then
62             ans:=max(ans,m-dis[i,s1]-dis[i,s2]-dis[i,j]-dis[j,t1]-dis[j,t2]);
63             if (dis[i,s1]+dis[i,j]+dis[j,t1]<=h1)and(dis[i,t2]+dis[i,j]+dis[j,s2]<=h2) then
64             ans:=max(ans,m-dis[i,s1]-dis[i,t2]-dis[i,j]-dis[j,s2]-dis[j,t1]);
65         end;
66     for i:=1 to n do
67         for j:=1 to n do if (dis[i,s1]+dis[i,t1]<=h1)and(dis[j,t2]+dis[j,s2]<=h2) then
68         ans:=max(ans,max(0,m-dis[i,s1]-dis[i,t1]-dis[j,s2]-dis[j,t2]));
69      if (h1>=dis[s1,t1])and(h2>=dis[s2,t2]) then ans:=max(ans,m-h1-h2);
70     writeln(ans);
71 end.

543C. Remembering Strings

You have multiset of n strings of the same length, consisting of lowercase English letters. We will say that those strings are easy to remember if for each string there is some position i and some letter c of the English alphabet, such that this string is the only string in the multiset that has letter c in position i.

For example, a multiset of strings {"abc", "aba", "adc", "ada"} are not easy to remember. And multiset {"abc", "ada", "ssa"} is easy to remember because:

  • the first string is the only string that has character c in position 3;
  • the second string is the only string that has character d in position 2;
  • the third string is the only string that has character s in position 2.

You want to change your multiset a little so that it is easy to remember. For aij coins, you can change character in the j-th position of thei-th string into any other lowercase letter of the English alphabet. Find what is the minimum sum you should pay in order to make the multiset of strings easy to remember.

  首先考试的时候想到状压DP但是只会平方的乱搞...

  况且看起来D更简单所以果断弃C..(事实证明这个想法太Naive

  实际上也非常好想...对于一个给定的状态用二进制表示

  我们可以从任意一位未满足题意的字符串操作,然而又要保证所有的为满足题意的字符串都被操作过

  因为显然和操作的顺序没有关系,因此没必要每次枚举操作哪位

  不妨每次都操作第一个不满足题意的位置

  很显然:如果当前位置是这一列中独一无二的字符,直接向下面的状态转移当前所得的最优解

  如果这一位不是,我们可以修改这一位,然后转移的时候加上花费

  但是有一种优秀的处理方法:就是假设一列中某个字符出现了x次,如果其余x-1个字符都修改掉了,剩下一个也就独一无二了

  然后我们再处理这种情况

  可以预处理出这一列中字符相同的位置、个数、总花费和最大花费

  显然,向下转移的状态是把这些位置都更新成满足题意,花费为总花费-最大花费

  这些都在预处理中实现,DP的时候就可以做到O(1)

  另外DP的顺序不能按照大小而是1的个数从小到大~

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 const int maxn=22,INF=1000000007,maxm=1100010;
 5 struct node{
 6     int tot,sum,mx,cov;
 7 }a[maxn][maxn];
 8 int n,m,f[maxm],len[maxm],q[maxm],tot[200],sum[200],mx[200],cov[200],map[maxn][maxn],p[maxn][maxn];
 9 char s[100];
10 int calc(int x){
11     int ans=0;
12     for (;x;x=x>>1) ans+=x&1;
13     return ans;
14 }
15
16 int max(int a,int b){
17     if (a>b) return a;
18     return b;
19 }
20
21 int min(int a,int b){
22     if (a<b) return a;
23     return b;
24 }
25
26 int getf(int x){
27     for (int i=1;i<=n;i++){
28         if ((x&1)==0) return (n-i+1);
29         x=x >> 1;
30     }
31 }
32 void sortf(int l,int r){
33     int i=l,j=r,mid=len[(l+r)>>1];
34     do{
35         while (i<r&&len[i]<mid) i++;
36         while (l<j&&len[j]>mid) j--;
37         if (i<=j){
38             len[0]=len[i];len[i]=len[j];len[j]=len[0];
39             q[0]=q[i];q[i]=q[j];q[j]=q[0];
40             i++;j--;
41         }
42     }while (i<=j);
43     if (i<r) sortf(i,r);
44     if (l<j) sortf(l,j);
45 }
46
47 int main(){
48     scanf("%d%d",&n,&m);gets(s);
49     char ch;
50     for (int i=1;i<=n;i++){
51         for (int j=1;j<=m;j++){
52             scanf("%c",&ch);
53             map[i][j]=ch;
54         }
55         gets(s);
56     }
57     for (int i=1;i<=n;i++)
58         for (int j=1;j<=m;j++) scanf("%d",&p[i][j]);
59     for (int i=1;i<=m;i++){
60         memset(cov,0,sizeof(cov));
61         memset(sum,0,sizeof(sum));
62         memset(mx,0,sizeof(mx));
63         memset(tot,0,sizeof(tot));
64         for (int j=1;j<=n;j++){
65             int ch=map[j][i];
66             cov[ch]+=1 << (n-j);
67             sum[ch]+=p[j][i];
68             mx[ch]=max(mx[ch],p[j][i]);
69             tot[ch]++;
70         }
71         for (int j=1;j<=n;j++){
72             int ch=map[j][i];
73             a[j][i].cov=cov[ch];
74             a[j][i].sum=sum[ch];
75             a[j][i].mx=mx[ch];
76             a[j][i].tot=tot[ch];
77         }
78 }
79     for (int i=0;i<=(1<<n)-2;i++) q[i+1]=i,len[i+1]=calc(q[i+1]);
80     sortf(1,(1<<n)-1);
81     memset(f,INF,sizeof(f));
82     f[0]=0;
83     for (int i=1;i<=(1<<n)-1;i++)if (f[q[i]]!=f[maxm-1]){
84         int x=getf(q[i]);
85         for (int j=1;j<=m;j++){
86             if (a[x][j].tot==1) f[q[i]|(1<<(n-x))]=min(f[q[i]|(1<<(n-x))],f[q[i]]);
87             else{
88                 f[q[i]|(1<<(n-x))]=min(f[q[i]|(1<<(n-x))],f[q[i]]+p[x][j]);
89                 f[q[i]|a[x][j].cov]=min(f[q[i]|a[x][j].cov],f[q[i]]+a[x][j].sum-a[x][j].mx);
90             }
91         }
92     }
93     printf("%d\n",f[(1<<n)-1]);
94     return 0;
95 }

543D. Road Improvement

The country has n cities and n - 1 bidirectional roads, it is possible to get from every city to any other one if you move only along the roads. The cities are numbered with integers from 1 to n inclusive.

All the roads are initially bad, but the government wants to improve the state of some roads. We will assume that the citizens are happy about road improvement if the path from the capital located in city x to any other city contains at most one bad road.

Your task is — for every possible x determine the number of ways of improving the quality of some roads in order to meet the citizens‘ condition. As those values can be rather large, you need to print each value modulo 1 000 000 007 (109 + 7).

  这道题订正了很久啊...

  其实还是非常容易想到做法的...

  对于每个叶子值赋为1(含义大概就是这样的道路为0的方案)

  然后对于一个节点,答案为所有(子树的答案+1)的乘积

  就这棵子树而言,除了下面的答案外,将连接子树与父亲节点的边毁掉也是一种方案,因此+1

  另外,子树与子树之前答案互不影响,所以可以相乘

  刚开始问自己:不是应该枚举一下有几棵子树要毁掉,分别毁掉哪几棵子树吗?那样复杂度就呵呵了啊...

  但是忘记了累计答案的时候,将道路为0也就是不毁掉任何边的方案累计了一个1

  他们的乘积恰好包括了所有的情况

  然后转换到n个节点..经典的两次dfs计算答案...

  但是还是WA了

  后来进行的一切努力...都是在拯救取模导致答案错误的问题

  首先一个简单的反例:

  如果有一棵子树的答案是模数-1,然后我们将子树+1连乘的时候答案就是0

  对于这个答案而言并没有错

  但是在我们第二次dfs计算上面部分的答案的时候,要将当前子树对父亲节点的贡献除掉

  这个时候就没有办法得到父亲节点在乘上模数之前的答案了

  

  改进的方法:

  增加一个标记vis,表示在向下的答案中出现的因子为模数的个数

  一旦发现儿子节点的答案+1=模数,那么这个标记+1,答案不动

  实际上还是错了..

    上面的操作是建立在儿子节点答案的vis=0的情况..

    因为如果儿子节点的答案中有模数这个因子了,那么它对父亲的贡献=1,相当于不变

  

  在第二次dfs的过程中

  如果当前节点的vis>0也就是有模数这个因子的话,我们是没有统计它对父亲的答案的

    如果父亲的vis=0,那么就直接统计答案,不需要除去当前节点的贡献

    如果父亲的vis>0,那么父亲的答案中有模数这个因子,然后就直接=1

  当前节点的vis=0

    如果当前节点的向下答案+1=模数的话

      如果父亲节点的vis=1也就是只有当前节点这一个模数因子

        那么此时父亲节点的答案正好是除去当前节点贡献的答案,统计即可

      否则,也就是父亲节点中除了当前节点的贡献之外还有别的模数因子,此时答案为1

    当前节点向下答案+1<>模数,此时是最正常的情况了...

    然而也要讨论父亲节点的vis标记

      如果它=0,那就直接统计答案,否则,答案=1

  1 const maxn = 400010;ttt = 10007;
  2 var n,e,i,j,x:longint;
  3     fa,next,link,vis:array[-1..maxn]of longint;
  4     a:array[-1..maxn]of record sum,sum2,x1,x2:int64;end;
  5     tt:int64;
  6
  7 procedure add(x,y:longint);
  8 begin
  9     inc(e);fa[e]:=y;next[e]:=link[x];link[x]:=e;
 10     inc(e);fa[e]:=x;next[e]:=link[y];link[y]:=e;
 11 end;
 12
 13 procedure ex_Euclid(a,b:int64;var x,y:int64);
 14 var t:int64;
 15 begin
 16     if b=0 then
 17     begin
 18         x:=1;y:=0;
 19         exit;
 20     end else
 21     begin
 22         ex_Euclid(b,a mod b,x,y);
 23         t:=x;x:=y;y:=t-(a div b)*y;
 24     end;
 25 end;
 26
 27 function inverse(a:int64):int64;
 28 var x,y:int64;
 29 begin
 30     ex_Euclid(a,tt,x,y);
 31     while x<0 do inc(x,tt);
 32     exit(x);
 33 end;
 34
 35 procedure dfs1(p:longint);
 36 var j:longint;
 37 begin
 38     a[p].sum:=1;vis[p]:=1;
 39     j:=link[p];
 40     while j<>0 do
 41     begin
 42         if vis[fa[j]]=0 then
 43         begin
 44             dfs1(fa[j]);
 45             if a[fa[j]].x1=0 then
 46             begin
 47              if a[fa[j]].sum+1=tt then inc(a[p].x1) else
 48              a[p].sum:=(a[p].sum*(a[fa[j]].sum+1))mod tt;
 49             end;
 50         end;
 51         j:=next[j];
 52     end;
 53 end;
 54
 55 procedure dfs2(fat,p:longint);
 56 var j:longint;
 57 begin
 58     vis[p]:=2;
 59     if fat<>0 then
 60     begin
 61         if a[p].x1<>0 then
 62         begin
 63                 if a[fat].x1=0 then a[p].sum2:=(a[fat].sum2*a[fat].sum+1) mod tt
 64                 else a[p].sum2:=1;
 65         end else
 66         begin
 67         if a[p].sum+1=tt then
 68         begin
 69                 if a[fat].x1>1 then a[p].sum2:=1 else
 70                         a[p].sum2:=(a[fat].sum2*a[fat].sum+1) mod tt;
 71         end else
 72         begin
 73                 if a[fat].x1>0 then a[p].sum2:=1 else
 74                 a[p].sum2:=(a[fat].sum2*a[fat].sum mod tt*inverse(a[p].sum+1)+1) mod tt;
 75         end;
 76         end;
 77     end else a[p].sum2:=1;
 78     j:=link[p];
 79     while j<>0 do
 80     begin
 81         if vis[fa[j]]=1 then
 82             dfs2(p,fa[j]);
 83         j:=next[j];
 84     end;
 85 end;
 86
 87 begin
 88     tt:=1000000007;
 89     readln(n);tt:=tt;
 90     e:=0;
 91     for i:=2 to n do
 92     begin
 93         read(x);add(i,x);
 94     end;
 95     fillchar(vis,sizeof(vis),0);
 96     dfs1(1);dfs2(0,1);
 97     tt:=tt;
 98     for i:=1 to n do if a[i].x1>0 then a[i].sum:=0;
 99     for i:=1 to n-1 do write((a[i].sum*a[i].sum2) mod tt,‘ ‘);
100     writeln(a[n].sum*a[n].sum2 mod tt);
101 end.


  

  还有十天就要二试了呢...完全没有反应过来啊...

  08/.May

      

    

  

 

时间: 2024-10-08 20:43:55

Codeforces Round #302 解题报告的相关文章

Codeforces Round #513解题报告(A~E)By cellur925

我是比赛地址 A:Phone Numbers $Description$:给你一串数字,问你能组成多少开头为8的11位电话号码. $Sol$:统计8的数量,与$n$%11作比较. 1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 5 using namespace std; 6 7 int n,len,cnt,ans; 8 char ch[1000]; 9 10 int main() 11 {

Codeforces Round #301 解题报告

感觉这次的题目顺序很不合理啊... A. Combination Lock Scrooge McDuck keeps his most treasured savings in a home safe with a combination lock. Each time he wants to put there the treasures that he's earned fair and square, he has to open the lock. The combination loc

Codeforces Round #302 (Div. 2) A B C

Codeforces Round #302 (Div. 2) A. Set of Strings 字符串 q 被称为 "beautiful" 当且仅当 q 可以被拆分成 k 个子串 (s1, s2, s3, ... , sk) 并且任意两个字串满足首字母不一样. 直接模拟,对 q 的每个字符进行判断,如果该字符在之前没有出现过,那么从它开始就可以组成一个新的字符串,并且计数,如果到了k 了则把之后的都归为一个字符串. #include <cstring> #include

水题 Codeforces Round #302 (Div. 2) A Set of Strings

题目传送门 1 /* 2 题意:一个字符串分割成k段,每段开头字母不相同 3 水题:记录每个字母出现的次数,每一次分割把首字母的次数降为0,最后一段直接全部输出 4 */ 5 #include <cstdio> 6 #include <iostream> 7 #include <cstring> 8 #include <string> 9 #include <algorithm> 10 using namespace std; 11 12 con

完全背包 Codeforces Round #302 (Div. 2) C Writing Code

题目传送门 1 /* 2 题意:n个程序员,每个人每行写a[i]个bug,现在写m行,最多出现b个bug,问可能的方案有几个 3 完全背包:dp[i][j][k] 表示i个人,j行,k个bug dp[0][0][0] = 1 表示不选择人的时候所有的bug的种类犯错误都只有一种 4 dp[i][j][k] += dp[i%2][j-1][k-a[i]]: 5 错误示范:dp[i][j][k] += dp[i-1][j-l][k-l*a[i]]; 其实要从上一行的状态推出,即少一行 6 内存限制,

Codeforces Round #302 (Div. 2) -- (A,B,C)

题目传送:Codeforces Round #302 (Div. 2) A. Set of Strings 思路:注意开头字母都不相同 AC代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include &

CFEducational Codeforces Round 66题解报告

CFEducational Codeforces Round 66题解报告 感觉丧失了唯一一次能在CF上超过wqy的机会QAQ A 不管 B 不能直接累计乘法打\(tag\),要直接跳 C 考虑二分第\(k\)小的值 那么问题就变成了 每一个数变成了\([x-mid,x+mid]\)的一段区间,如果有一个位置被覆盖了超过\(k\)次 那么\(mid\)一定合法 类似括号匹配 每次碰到左端点就贡献+1 右端点就统计答案然后-1 维护答案的同时顺便维护位置就好了 #include<cstdio>

Codeforces Round #472 (based on VK Cup 2018 Round 2)解题报告

A. Mystical Mosaic 题目大意: 给一个空白矩阵,每次可以选一些行和一些列并让他们的交点涂黑,每次选的行和列不能有交集. 给出最后的矩阵样子,问能不能经过若干次以上操作后得到最后的矩阵. 思路: 每一行都可以确定哪些列必须被覆盖记为Si,任意两个不同的行之间要么S相等要么相交为空集. 所以我们要做的就是确定任意两行,他们的S要么相等要么相交为空集,这是答案为Yes的充要条件. 代码: 1 #include <bits/stdc++.h> 2 using namespace st

hacker cup 2015 Round 1 解题报告

A:求区间内素因子个数等于n的数有多少个 解题思路:筛法 解题代码: 1 // File Name: a.cpp 2 // Author: darkdream 3 // Created Time: 2015年01月18日 星期日 13时54分20秒 4 5 #include<vector> 6 #include<list> 7 #include<map> 8 #include<set> 9 #include<deque> 10 #include&