Codeforces Round #302 解题报告
感觉今天早上虽然没有睡醒但是效率还是挺高的...
Pas和C++换着写...
544A. Set of StringsYou 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
var i,k,j:longint;
vis:array['a'..'z']of boolean;
v:array[-..]of boolean;
s:ansistring; begin
readln(k);
readln(s);
fillchar(vis,sizeof(vis),true);
fillchar(v,sizeof(v),true);
for i:= to length(s) do if vis[s[i]] then
begin
vis[s[i]]:=false;v[i]:=false;dec(k);
if k= then break;
end;
if k> then writeln('NO') else
begin
writeln('YES');
i:=;
while i<=length(s) do
begin
write(s[i]);
j:=i+;
while (j<=length(s))and(v[j]) do
begin
write(s[j]);
inc(j);
end;
writeln;
i:=j;
end;
end;
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.
又是一道看样例就会思路乱掉的题..
非常简单,每个小岛占一格就好了..
直接按照横纵坐标和差的奇偶性判断是否放沙
var i,j,n,k:longint;
begin
readln(n,k);
if k>(n*n+) >> then writeln('NO') else
begin
writeln('YES');
for i:= to n do
begin
for j:= to n do if ((i+j) and =)and(k>) then
begin
write('L');dec(k);
end else write('S');
writeln;
end;
end;
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...甚至想要去写二进制背包这种两年没写过的东西...
然而不确定数量的背包直接正序就好了啊...
#include<cstdio>
#include<cstdlib>
#include<cstring>
int a[],f[][];
int main(){
int n,m,b,tt;
scanf("%d%d%d%d",&n,&m,&b,&tt);
for (int i=;i<=n;i++) scanf("%d",&a[i]);
f[][] = ;
for (int i=;i<=n;i++)
for (int j=;j<=m;j++)
for (int k=a[i];k<=b;k++) f[j][k]=(f[j][k]+f[j-][k-a[i]])%tt;
int ans=;
for (int i=;i<=b;i++) ans=(ans+f[m][i])%tt;
printf("%d\n",ans);
return ;
}
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求出多源最短路
将上面几种方法尝试一下然后更新出答案
然而还要注意两个点分别连接的不一定都是起点或都是终点,要讨论一下...
const maxn = ;maxm=;INF=;
var fa,next:array[-..maxm]of longint;
link,opt:array[-..maxn]of longint;
vis:array[-..maxn]of boolean;
dis:array[-..maxn,-..maxn]of longint;
ans,s1,t1,h1,s2,t2,h2,n,m,e,i,x,y,j:longint; procedure add(x,y:longint);
begin
inc(e);fa[e]:=y;next[e]:=link[x];link[x]:=e;
inc(e);fa[e]:=x;next[e]:=link[y];link[y]:=e;
end; function min(a,b:longint):longint;
begin
if a<b then exit(a) else exit(b);
end; function max(a,b:longint):longint;
begin
if a>b then exit(a) else exit(b);
end; procedure bfs(s:longint);
var head,tail,x,j,i:longint;
begin
for i:= to n do dis[i,s]:=INF;
fillchar(vis,sizeof(vis),true);
head:=;tail:=;dis[s,s]:=;vis[s]:=false;opt[]:=s;
while head<>tail do
begin
inc(head);
x:=opt[head];j:=link[x];
while j<> do
begin
if vis[fa[j]] then
begin
vis[fa[j]]:=false;
dis[fa[j],s]:=dis[x,s]+;
inc(tail);opt[tail]:=fa[j];
end;
j:=next[j];
end;
end;
end; begin
readln(n,m);
e:=;
for i:= to m do
begin
readln(x,y);add(x,y);
end;
for i:= to n do bfs(i);
readln(s1,t1,h1);readln(s2,t2,h2);
ans:=-;
if (dis[s1,t1]<=h1)and(dis[s2,t2]<=h2) then ans:=max(ans,max(,m-dis[s1,t1]-dis[s2,t2]));
for i:= to n do
for j:= to n do
begin
if (dis[i,s1]+dis[i,j]+dis[j,t1]<=h1)and(dis[i,s2]+dis[i,j]+dis[j,t2]<=h2) then
ans:=max(ans,m-dis[i,s1]-dis[i,s2]-dis[i,j]-dis[j,t1]-dis[j,t2]);
if (dis[i,s1]+dis[i,j]+dis[j,t1]<=h1)and(dis[i,t2]+dis[i,j]+dis[j,s2]<=h2) then
ans:=max(ans,m-dis[i,s1]-dis[i,t2]-dis[i,j]-dis[j,s2]-dis[j,t1]);
end;
for i:= to n do
for j:= to n do if (dis[i,s1]+dis[i,t1]<=h1)and(dis[j,t2]+dis[j,s2]<=h2) then
ans:=max(ans,max(,m-dis[i,s1]-dis[i,t1]-dis[j,s2]-dis[j,t2]));
if (h1>=dis[s1,t1])and(h2>=dis[s2,t2]) then ans:=max(ans,m-h1-h2);
writeln(ans);
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的个数从小到大~
[UPD.05.13]DP的顺序实际上可以直接从小到大...因为不管哪一位加了多少个1肯定比当前数大..
#include<cstdio>
#include<cstdlib>
#include<cstring>
const int maxn=,INF=,maxm=;
struct node{
int tot,sum,mx,cov;
}a[maxn][maxn];
int n,m,f[maxm],len[maxm],q[maxm],tot[],sum[],mx[],cov[],map[maxn][maxn],p[maxn][maxn];
char s[];
int calc(int x){
int ans=;
for (;x;x=x>>) ans+=x&;
return ans;
} int max(int a,int b){
if (a>b) return a;
return b;
} int min(int a,int b){
if (a<b) return a;
return b;
} int getf(int x){
for (int i=;i<=n;i++){
if ((x&)==) return (n-i+);
x=x >> ;
}
}
void sortf(int l,int r){
int i=l,j=r,mid=len[(l+r)>>];
do{
while (i<r&&len[i]<mid) i++;
while (l<j&&len[j]>mid) j--;
if (i<=j){
len[]=len[i];len[i]=len[j];len[j]=len[];
q[]=q[i];q[i]=q[j];q[j]=q[];
i++;j--;
}
}while (i<=j);
if (i<r) sortf(i,r);
if (l<j) sortf(l,j);
} int main(){
scanf("%d%d",&n,&m);gets(s);
char ch;
for (int i=;i<=n;i++){
for (int j=;j<=m;j++){
scanf("%c",&ch);
map[i][j]=ch;
}
gets(s);
}
for (int i=;i<=n;i++)
for (int j=;j<=m;j++) scanf("%d",&p[i][j]);
for (int i=;i<=m;i++){
memset(cov,,sizeof(cov));
memset(sum,,sizeof(sum));
memset(mx,,sizeof(mx));
memset(tot,,sizeof(tot));
for (int j=;j<=n;j++){
int ch=map[j][i];
cov[ch]+= << (n-j);
sum[ch]+=p[j][i];
mx[ch]=max(mx[ch],p[j][i]);
tot[ch]++;
}
for (int j=;j<=n;j++){
int ch=map[j][i];
a[j][i].cov=cov[ch];
a[j][i].sum=sum[ch];
a[j][i].mx=mx[ch];
a[j][i].tot=tot[ch];
}
}
for (int i=;i<=(<<n)-;i++) q[i+]=i,len[i+]=calc(q[i+]);
sortf(,(<<n)-);
memset(f,INF,sizeof(f));
f[]=;
for (int i=;i<=(<<n)-;i++)if (f[q[i]]!=f[maxm-]){
int x=getf(q[i]);
for (int j=;j<=m;j++){
if (a[x][j].tot==) f[q[i]|(<<(n-x))]=min(f[q[i]|(<<(n-x))],f[q[i]]);
else{
f[q[i]|(<<(n-x))]=min(f[q[i]|(<<(n-x))],f[q[i]]+p[x][j]);
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);
}
}
}
printf("%d\n",f[(<<n)-]);
return ;
}
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
const maxn = ;ttt = ;
var n,e,i,j,x:longint;
fa,next,link,vis:array[-..maxn]of longint;
a:array[-..maxn]of record sum,sum2,x1,x2:int64;end;
tt:int64; procedure add(x,y:longint);
begin
inc(e);fa[e]:=y;next[e]:=link[x];link[x]:=e;
inc(e);fa[e]:=x;next[e]:=link[y];link[y]:=e;
end; procedure ex_Euclid(a,b:int64;var x,y:int64);
var t:int64;
begin
if b= then
begin
x:=;y:=;
exit;
end else
begin
ex_Euclid(b,a mod b,x,y);
t:=x;x:=y;y:=t-(a div b)*y;
end;
end; function inverse(a:int64):int64;
var x,y:int64;
begin
ex_Euclid(a,tt,x,y);
while x< do inc(x,tt);
exit(x);
end; procedure dfs1(p:longint);
var j:longint;
begin
a[p].sum:=;vis[p]:=;
j:=link[p];
while j<> do
begin
if vis[fa[j]]= then
begin
dfs1(fa[j]);
if a[fa[j]].x1= then
begin
if a[fa[j]].sum+=tt then inc(a[p].x1) else
a[p].sum:=(a[p].sum*(a[fa[j]].sum+))mod tt;
end;
end;
j:=next[j];
end;
end; procedure dfs2(fat,p:longint);
var j:longint;
begin
vis[p]:=;
if fat<> then
begin
if a[p].x1<> then
begin
if a[fat].x1= then a[p].sum2:=(a[fat].sum2*a[fat].sum+) mod tt
else a[p].sum2:=;
end else
begin
if a[p].sum+=tt then
begin
if a[fat].x1> then a[p].sum2:= else
a[p].sum2:=(a[fat].sum2*a[fat].sum+) mod tt;
end else
begin
if a[fat].x1> then a[p].sum2:= else
a[p].sum2:=(a[fat].sum2*a[fat].sum mod tt*inverse(a[p].sum+)+) mod tt;
end;
end;
end else a[p].sum2:=;
j:=link[p];
while j<> do
begin
if vis[fa[j]]= then
dfs2(p,fa[j]);
j:=next[j];
end;
end; begin
tt:=;
readln(n);tt:=tt;
e:=;
for i:= to n do
begin
read(x);add(i,x);
end;
fillchar(vis,sizeof(vis),);
dfs1();dfs2(,);
tt:=tt;
for i:= to n do if a[i].x1> then a[i].sum:=;
for i:= to n- do write((a[i].sum*a[i].sum2) mod tt,' ');
writeln(a[n].sum*a[n].sum2 mod tt);
end.
还有十天就要二试了呢...完全没有反应过来啊...
08/.May
Codeforces Round #302 解题报告的更多相关文章
- Codeforces Round #300 解题报告
呜呜周日的时候手感一直很好 代码一般都是一遍过编译一遍过样例 做CF的时候前三题也都是一遍过Pretest没想着去检查... 期间姐姐提醒说有Announcement也自信不去看 呜呜然后就FST了 ...
- Codeforces Round #513解题报告(A~E)By cellur925
我是比赛地址 A:Phone Numbers $Description$:给你一串数字,问你能组成多少开头为8的11位电话号码. $Sol$:统计8的数量,与$n$%11作比较. #include&l ...
- Codeforces Round #301 解题报告
感觉这次的题目顺序很不合理啊... A. Combination Lock Scrooge McDuck keeps his most treasured savings in a home sa ...
- 完全背包 Codeforces Round #302 (Div. 2) C Writing Code
题目传送门 /* 题意:n个程序员,每个人每行写a[i]个bug,现在写m行,最多出现b个bug,问可能的方案有几个 完全背包:dp[i][j][k] 表示i个人,j行,k个bug dp[0][0][ ...
- 构造 Codeforces Round #302 (Div. 2) B Sea and Islands
题目传送门 /* 题意:在n^n的海洋里是否有k块陆地 构造算法:按奇偶性来判断,k小于等于所有点数的一半,交叉输出L/S 输出完k个L后,之后全部输出S:) 5 10 的例子可以是这样的: LSLS ...
- 水题 Codeforces Round #302 (Div. 2) A Set of Strings
题目传送门 /* 题意:一个字符串分割成k段,每段开头字母不相同 水题:记录每个字母出现的次数,每一次分割把首字母的次数降为0,最后一段直接全部输出 */ #include <cstdio> ...
- CFEducational Codeforces Round 66题解报告
CFEducational Codeforces Round 66题解报告 感觉丧失了唯一一次能在CF上超过wqy的机会QAQ A 不管 B 不能直接累计乘法打\(tag\),要直接跳 C 考虑二分第 ...
- Codeforces Global Round 1 解题报告
A 我的方法是: #include<bits/stdc++.h> using namespace std; #define int long long typedef long long ...
- Codeforces Educational Round 81 解题报告
前置扯淡 赛前:这场\(Div2\)呀,那我写\(3\)题就行,\(D\)题尽力就好 赛中:啊啊,\(ABC\)我全过了\(pretest\),我太强了!!这把上蓝稳了 赛后:\(woc\),为啥被\ ...
随机推荐
- TCP 的有限状态机
TCP 有限状态机的图中每一个方框都是 TCP 可能具有的状态. 每个方框中的大写英文字符串是 TCP 标准所使用的 TCP 连接状态名. 状态之间的箭头表示可能发生的状态变迁. 箭头旁边的字,表明引 ...
- LintCode-365.二进制中有多少个1
二进制中有多少个1 计算在一个 32 位的整数的二进制表式中有多少个 1. 样例 给定 32 (100000),返回 1 给定 5 (101),返回 2 给定 1023 (111111111),返回 ...
- 整理下本周工作中遇到的疑问;uid/euid/suid;docker镜像管理
1.系统中的父子进程关系,以及docker是如何处理的这种父子进程关系,线上问题发现,子进程长时间得不到退出. 2.调用system系统调用发生了啥事情,发现大量的页表拷贝. 3.通过shell命令通 ...
- shit antd & Merry Christmas bug
shit antd & Merry Christmas bug https://github.com/ant-design/ant-design/issues/13098 antd 玩大了? ...
- [剑指Offer] 58.对称的二叉树
题目描述 请实现一个函数,用来判断一颗二叉树是不是对称的.注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的. [思路]递归,关键是isSame函数中的最后一句 /* struct Tree ...
- [剑指Offer] 51.构建乘积数组
题目描述 给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],其中B中的元素B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1].不 ...
- bzoj3998-弦论
给定一个长度为\(n(n\le 5\times 10^5)\)的字符串,求它的第\(k\)小字串.有两种模式: \(Type=0\),不同位置的相同字串只算一个 \(Type=1\),不同位置相同字串 ...
- BZOJ 1927 星际竞速(费用流)
考虑费用流,题目要求走n个点都走完且恰好一次,显然流量的限制为n. 建立源点s和汇点t,并把每个星球拆成两个点i和i',分别表示已到达该点和经过该点. 对于能力爆发,建边(s,i',1,w). 对应高 ...
- bzoj2676 Contra
题意: 给定N,R,Q,S 有N个关卡,初始有Q条命,且任意时刻最多只能有Q条命 每通过一个关卡,会得到u分和1条命,其中u=min(最近一次连续通过的关数,R) 若没有通过这个关卡,将失去一条命,并 ...
- Python替换字符串中的反斜杠\
s = 'cdp\nd' result = eval(repr(s).replace('\\', '@')) print(result) repr() 函数可以将字符串转换为python的原始字符串( ...