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\),为啥被\ ...
随机推荐
- 简单理解SQL Server锁机制
多个用户同时对数据库的并发操作时,可能会遇到下面几种情况,导致数据前后不一致: 1,A.B事务同时对同一个数据进行修改,后提交的人的修改结果会破坏先提交的(丢失更新): 2,事务A修改某一条数据还未提 ...
- Java 8中 基本数据类型
1)四种整数类型(byte.short.int.long): byte:8 位,用于表示最小数据单位,如文件中数据,-128~127 short:16 位,很少用,-32768 ~ 327 ...
- vmware 虚拟机下安装centOS7.0
当时安装的是 CentOS-7.0-1406-x86_64-DVD.iso 这个版本的镜像,提示: 您已经配置此虚拟机使用64位客户操作系统.但是64位操作系统不可用.此主机具有虚拟化支持能力的,可是 ...
- C语言指针【转】
一.C语言指针的概念 在计算机中,所有的数据都是存放在存储器中的.一般把存储器中的一个字节称为一个内存单元,不同的数据类型所占用的内存单元数不等,如整型量占2个单元,字符量占1个单元等,在前面已有详细 ...
- Python 基本数据结构
Python基本数据结构 数据结构:通俗点儿说,就是存储数据的容器.这里主要介绍Python的4种基本数据结构:列表.元组.字典.集合: 格式如下: 列表:list = [val1, val2, va ...
- 新版chrome touch警告处理办法
最近做项目经常在 chrome 的控制台看到如下提示: Unable to preventDefault inside passive event listener due to target bei ...
- [六省联考2017]分手是祝愿 期望DP
表示每次看见期望的题就很懵逼... 但是这题感觉还是值得一做,有可借鉴之处 要是下面这段文字格式不一样的话(虽然好像的确不一样,我也不知道为什么,是直接从代码里面复制出来的,因为我一般都是习惯在代码里 ...
- Android 解决setRequestedOrientation之后手机屏幕的旋转不触发onConfigurationChanged方法
最近在做播放器的时候遇到一个问题,在屏幕方向改变之后需要切换播放器全屏/非全屏的时候,在重写了onConfigurationChanged方法并在manifest.xml配置文件中添加 android ...
- Android View 绘制刷新流程分析
Android中对View的更新有很多种方式,使用时要区分不同的应用场合.1.不使用多线程和双缓冲 这种情况最简单,一般只是希望在View发生改变时对UI进行重绘.你只需显式地调用View对 ...
- LOJ2587:[APIO2018]铁人两项——题解
https://loj.ac/problem/2587#submit_code (题面来自LOJ) 考试时候发觉树很可做,并且写了一个dp骗到了树的分. 苦于不会圆方树……现在回来发现这题还是很可做的 ...