Codeforces 1131 (div 2)
链接:http://codeforces.com/contest/1131
A Sea Battle#
利用良心出题人给出的图,不难看出答案为\(2*(h1+h2)+2*max(w1,w2)+4\)由于\(w2 \leq w1\),所以答案为\(2*(h1+h2)+2*w1+4\)
#include<cstdio>
int w1,h1,h2,w2,ans;
int main(){
scanf("%d%d%d%d",&w1,&h1,&w2,&h2);
ans+=(h1+h2)*2+w1*2+4;
printf("%d\n",ans);
}
B Draw#
这本质上可以说是一道贪心题吧,我们稍微分类讨论一下
我们假设上一轮的结果为\(x:y\)显然可以分为3种情况,\(x<y,x=y,x>y\)
\(x<y\)和\(x>y\)本质一样我们只讨论一种
\(x<y\)对于新一轮的比分\(p:q\)
若\(y>p\),那么说明在这几轮比赛中根本不可能出现,继续做就行,
否则,我们可以让前一个人赢,赢球一时爽,一直赢球一直爽,赢到两个人比分一样,然后你拍一,我拍一就好了
\(x=y\)的话,我们发现就是上面的子问题,直接你拍一,我拍一
#include<cstdio>
#include<algorithm>
using namespace std;
int ans=1,la,lb,a,b,n;
int main(){
scanf("%d",&n);
for (int i=1;i<=n;i++){
scanf("%d%d",&a,&b);
if (a==la&&b==lb)continue;
if (la>lb){
if (b<la){
la=a,lb=b;
continue;
}
ans+=min(a,b)-la+1;
la=a;lb=b;
}
else if (la<lb){
if (a<lb){
la=a,lb=b;
continue;
}
ans+=min(a,b)-lb+1;
la=a;lb=b;
}
else {
ans+=min(a,b)-la;
la=a,lb=b;
}
}
printf("%d\n",ans);
}
C Birthday#
这题啊,看起来有点难,其实只是纸老抚
数据范围只有100,首先考虑乱搞
发现乱搞凉了,怎么办?只会std::sort的选手突然想到,先排序!
排完序了怎么办呢?我们考虑贪心地将排序后奇数位的数先按顺序填下去,然后将偶数位的数反过来填下去,这样就对了
为什么呢?
我们尝试证明一下这个贪心
我们规定,我们填下去的数是从小到大填的,如果我们现在按这样填不是最优解,那么说明我们存在一种合法方案,使得让两个排完序后相邻的数在环中也相邻,并且这个方案更优
我们设这位为第i位,则i和i+1在环中相邻
然而我们意识到,如果这个方案要更优,则说明i与i+2是原来方案中差距最大的两个数,这样我们调整后才能得到一个更优的方案,一定不会变优
我们开始考虑填入i+2,我们发现,i+2只能和i+1相邻,否则就会和一个小于等于i的数字相邻,那么这个新方案就一定不会比前面那个更优,了不起一样优嘛
我们归纳一下,之后的每个数都存在这个问题,不能与小于等于i的数相邻,这样的环显然是不存在的,所以这个贪心是对的
(不知道我在瞎bb啥,但是应该是对的,考场上我画了个图,现在懒得画了,大家意会一下吧略略略)
#include<cstdio>
#include<algorithm>
int n,a[105],b[105],f[105];
int main(){
scanf("%d",&n);
for (int i=1;i<=n;i++)scanf("%d",&a[i]);
std::sort(a+1,a+n+1);
b[1]=a[1];
int mid=(n>>1)+1;
b[(n>>1)+1]=a[n];f[1]=f[n]=1;
for (int i=2,j=3;i<mid;i++,j+=2)b[i]=a[j],f[j]=1;
for (int i=n,j=1;i>mid;j++)if (!f[j])b[i--]=a[j];
for (int i=1;i<=n;i++)printf("%d ",b[i]);
}
D Gourmet choice#
乍一看,差分约束!
然后发现不会建图
怎么办
考虑乱搞
我们先考虑假如给出的条件都是大于小于,那么要怎么做
由NOIP2013 普及组 车站分级我们可以得到,拓扑排序!
将所有点按拓扑序编号就行了
如何处理等号?
把用等号连接的点强行压成一个点
当拓扑排序失败或出现自环则输出“No”,否则“Yes”,然后拓扑编号输出
#include<cstdio>
#include<vector>
std::vector<int> v[2050];
struct r{
int to,last;
}e[4000050];
int f[2050],dep[2050],num=1,mp[2050][2050],head[2050],h=1,q[2050],ans[2050],d[2050],t;
char s[1050][1050];
void add(int u,int v){e[num].to=v;e[num].last=head[u];head[u]=num++;}
int get_fa(int u){return f[u]==u?u:f[u]=get_fa(f[u]);}
int main(){
int n,m;
scanf("%d%d",&n,&m);
for (int i=1;i<=n+m;i++)f[i]=i;
for (int i=1;i<=n;i++)scanf("%s",s[i]);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)if (s[i][j-1]=='='){
int fu=get_fa(i),fv=get_fa(j+n);
f[fv]=fu;
}
for (int i=1;i<=n+m;i++)v[get_fa(i)].push_back(i);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)if (s[i][j-1]=='<'){
int fu=get_fa(i),fv=get_fa(j+n);
if (fu==fv){
printf("No\n");
return 0;
}
if (!mp[fu][fv])add(fu,fv),d[fv]++;
}
else if (s[i][j-1]=='>'){
int fu=get_fa(i),fv=get_fa(j+n);
if (fu==fv){
printf("No\n");
return 0;
}
if (!mp[fu][fv])add(fv,fu),d[fu]++;
}
for (int i=1;i<=n+m;i++)if (f[i]==i&&!d[i])q[++t]=i,dep[i]=1;
while (h<=t){
int u=q[h++];
for (int i=head[u];i;i=e[i].last){
d[e[i].to]--;
if (!d[e[i].to]){
dep[e[i].to]=dep[u]+1;
q[++t]=e[i].to;
}
}
}
for (int i=1;i<=n+m;i++)if (f[i]==i&&!dep[i]){
printf("No\n");
return 0;
}
printf("Yes\n");
for (int i=1;i<=n+m;i++)
for (int j=v[i].size()-1;j>=0;j--)ans[v[i][j]]=dep[i];
for (int i=1;i<=n+m;i++){
printf("%d ",ans[i]);
if (i==n)putchar('\n');
}
}
E String Multiplication#
由于时间问题,蒟蒻博主并没有时间看完这道题的题面(由于当场F题过的人多所以先跳题了)
考后发现,这题并不难
我们读完题目可以发现,原来的串相邻的位置都被隔开了!利用这个就可以解决这题了
我们可以发现,对于新串,对我们有用的信息只有最左有几个相同字母,最右有几个相同字母以及每种字母最多有多少个连续的
于是我们可以分字母统计这个问题
若新串首尾不同,则首字母的连续长度更新为max{新串最左的连续长度+1,串中该字母的最长连续长度}(最后一个字母也是一样的)
如果相同(该串不止含有一种字母),则首尾字母的最长连续长度为max{新串最左的连续长度+1+最右连续长度,串中该字母的最长连续长度}
若该串中只有一种字母,则这种字母连续长度更新为max{原串中连续长度*(新串长度+1),1}
当然只要出现过的字母连续长度最少都为1,出现过的字母记得和1取max就好了
按字母更新完后,在这些字母中找一个连续长度最大的输出长度就好了
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n,cnt[35],p[35],ans;
char s[100050];
int main(){
scanf("%d",&n);
for (int i=1;i<=n;i++){
scanf("%s",s);
int len=strlen(s),tmp=1,ft,flag=0;
for (int j=0;j<26;j++)p[j]=(cnt[j]!=0);
for (int j=1;j<len;j++)if (s[j]==s[j-1])tmp++;
else{
if (!flag)ft=tmp,flag=1;
p[s[j-1]-'a']=max(p[s[j-1]-'a'],tmp);
tmp=1;
}
p[s[len-1]-'a']=max(p[s[len-1]-'a'],tmp);
if (!flag)p[s[0]-'a']=max(tmp+cnt[s[0]-'a']*tmp+cnt[s[0]-'a'],p[s[0]-'a']);
else if (s[0]==s[len-1])p[s[0]-'a']=max(cnt[s[0]-'a']?tmp+ft+1:0,p[s[0]-'a']);
else p[s[0]-'a']=max((cnt[s[0]-'a']!=0)+ft,p[s[0]-'a']),p[s[len-1]-'a']=max((cnt[s[len-1]-'a']!=0)+tmp,p[s[len-1]-'a']);
for (int j=0;j<26;j++)cnt[j]=p[j];
}
for (int i=0;i<26;i++)ans=max(cnt[i],ans);
printf("%d\n",ans);
}
F Asya And Kittens#
蒟蒻博主因为数组开小,差点没过!心态爆炸
这题呢,用心感受一下题目,每次把两个东西合并起来,是不是很像并查集
没错,这题就是用的并查集
首先我们把每个点初始化,合并的时候考虑新建一个点\(tmp\),把这次合并的两个点\(fu,fv\)都连到这个新点\(tmp\)上,并且\(f[tmp]=f[fu]=f[fv]=tmp\)
然后\(add\_edge(tmp,fu),add\_edge(tmp,fv)\)
我们做完之后得到了什么呢,每次操作都增加了一层,一个点向两个点连边,这不就是棵树吗
我们用\(dfs\)遍历这棵树,每次遇到\(id \leq n\)的就加入答案就行了,由于这棵树形态非常优美,所以做出来就是对的
#include<cstdio>
struct r{
int to,last;
}e[300050];
int num=1,head[300050],ans[150050],cnt,tmp,n,f[300050],x,y;
void add(int u,int v){
e[num].to=v;e[num].last=head[u];head[u]=num++;
}
int get_fa(int u){return f[u]==u?u:f[u]=get_fa(f[u]);}
void dfs(int u){
if (u<=n)ans[++cnt]=u;
for (int i=head[u];i;i=e[i].last)dfs(e[i].to);
}
int main(){
scanf("%d",&n);
tmp=n;
for (int i=1;i<=n;i++)f[i]=i;
for (int i=1;i<n;i++){
scanf("%d%d",&x,&y);
int fu=get_fa(x),fv=get_fa(y);
if (fu!=fv){
tmp++;
add(tmp,fv),add(tmp,fu);
f[tmp]=f[fu]=f[fv]=tmp;
}
}
dfs(tmp);
for (int i=1;i<=n;i++)printf("%d ",ans[i]);
}
G Most Dangerous Shark#
看了好几次题解都没看懂,我真是太弱啦
最后买了一包山楂片,边吃,终于看懂了题解(这绝对不是帮山楂片打广告,正经博主怎么可能打广告呢)
第一次做手动栈大题,题好神啊
首先我们可以写出最原始的dp方程\(dp[i]=min(dp[l[i]-1]+c[i],dp[j-1]+c[j](j<i\leq r[j]))\)
其中\(l[i]\)表示将第\(i\)个骨牌向左推倒能推到的最左的骨牌,\(r[i]\)当然就是向右推到最右的啦
我们现在已经可以得到一个线段树解法了,但是本题需要我们在\(O(n)\)的复杂度内解决这个问题
我们可以尝试使用栈,我们先倒过来做,将元素压栈,若遇到\(i\leq s[top]+h[s[top]]\)那么我们就弹栈并且将弹出的元素的\(l[i]\)设为\(i+1\)
然后我们就得到了\(l[i]\)
而对于\(r[i]\)的话,其实我们没必要把它求出来,只要边做边dp,然后维护一个栈中前缀最小值就好啦
#include<cstdio>
#include<vector>
#include<algorithm>
#define ll long long
std::vector <int> v1[250050],v2[250050];
int k[250050],n,m,l[10000050],t,h[10000050],v,tmp,s[10000050];
ll mn[10000050],c[10000050],dp[10000050];
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++){
scanf("%d",&k[i]);
for (int j=k[i];j;j--)scanf("%d",&v),v1[i].push_back(v);
for (int j=k[i];j;j--)scanf("%d",&v),v2[i].push_back(v);
}
int q,id,mul;
scanf("%d",&q);
for (int i=1;i<=q;i++){
scanf("%d%d",&id,&mul);
for (int j=0;j<k[id];j++){
++tmp;h[tmp]=v1[id][j];
c[tmp]=v2[id][j]*1ll*mul;
}
}
for (int i=m;i>=1;i--){
while (t&&i<=s[t]-h[s[t]])l[s[t--]]=i+1;
s[++t]=i;
}
while (t)l[s[t--]]=1;mn[0]=1e18;
for (int i=1;i<=m;i++){
while (t&&i>=s[t]+h[s[t]])t--;
dp[i]=std::min(dp[l[i]-1]+c[i],mn[t]);
s[++t]=i;
mn[t]=std::min(mn[t-1],dp[i-1]+c[i]);
}
printf("%lld\n",dp[m]);
}
Codeforces 1131 (div 2)的更多相关文章
- Codeforces #344 Div.2
Codeforces #344 Div.2 Interview 题目描述:求两个序列的子序列或操作的和的最大值 solution 签到题 时间复杂度:\(O(n^2)\) Print Check 题目 ...
- Codeforces #345 Div.1
Codeforces #345 Div.1 打CF有助于提高做题的正确率. Watchmen 题目描述:求欧拉距离等于曼哈顿距离的点对个数. solution 签到题,其实就是求有多少对点在同一行或同 ...
- Codeforces Beta Round #27 (Codeforces format, Div. 2)
Codeforces Beta Round #27 (Codeforces format, Div. 2) http://codeforces.com/contest/27 A #include< ...
- Codeforces#441 Div.2 四小题
Codeforces#441 Div.2 四小题 链接 A. Trip For Meal 小熊维尼喜欢吃蜂蜜.他每天要在朋友家享用N次蜂蜜 , 朋友A到B家的距离是 a ,A到C家的距离是b ,B到C ...
- codeforces #592(Div.2)
codeforces #592(Div.2) A Pens and Pencils Tomorrow is a difficult day for Polycarp: he has to attend ...
- codeforces #578(Div.2)
codeforces #578(Div.2) A. Hotelier Amugae has a hotel consisting of 1010 rooms. The rooms are number ...
- codeforces #577(Div.2)
codeforces #577(Div.2) A Important Exam A class of students wrote a multiple-choice test. There are ...
- codeforces #332 div 2 D. Spongebob and Squares
http://codeforces.com/contest/599/problem/D 题意:给出总的方格数x,问有多少种不同尺寸的矩形满足题意,输出方案数和长宽(3,5和5,3算两种) 思路:比赛的 ...
- Codeforces 1131 F. Asya And Kittens-双向链表(模拟或者STL list)+并查集(或者STL list的splice()函数)-对不起,我太菜了。。。 (Codeforces Round #541 (Div. 2))
F. Asya And Kittens time limit per test 2 seconds memory limit per test 256 megabytes input standard ...
随机推荐
- Linux下汇编语言学习笔记63 ---
这是17年暑假学习Linux汇编语言的笔记记录,参考书目为清华大学出版社 Jeff Duntemann著 梁晓辉译<汇编语言基于Linux环境>的书,喜欢看原版书的同学可以看<Ass ...
- vagrant的学习 之 ThinkPHP5.1
vagrant的学习 之 ThinkPHP5.1 本文根据慕课网的视频教程练习,感谢慕课网! 慕课视频学习地址:https://www.imooc.com/video/14218. 慕课的参考文档地址 ...
- n个点中求任意两点组成斜率的最大值
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1100 首先按x坐标排序,然后相邻的三个点A,B,C 组成的三条直线必然有 ...
- C++ fill 和memset
以下内容来自www.cplusplus.com--------------------------------------------------- FILL: template <class ...
- Bad Hair Day-POJ3250(简单的入栈出栈)
Description Some of Farmer John's N cows (1 ≤ N ≤ 80,000) are having a bad hair day! Since each cow ...
- Oracle中,利用sql语句中的函数实现保留两位小数和四舍五入保留两位小数
Oracle中,利用sql语句中的函数实现保留两位小数和四舍五入保留两位小数: select trunc(1.23856789,2) from dual round(m,n) 可以四舍五入 trunc ...
- 华为AR1220
今天刚刚收到华为AR1220,以为直接就可以用web界面管理,结果开机后才知道web管理界面需要激活.下面简单分享这个过程:*** 用控制台线(一边RJ45,一边9针串)连接Router consol ...
- [Debug] Inspect and Style an Element in DevTools that Normally Disappears when Inactive
It’s handy to inspect an element in your browser’s DevTools when you need to experiment or tweak it’ ...
- 《编程导论(Java)·3.1.2 方法》之 副作用
4. 副作用 在一些语言如Pascal中,子程序被分成两种:函数和过程.尽管Java没有强制性地要求将方法区分为命令和函数.然而这样的差别对于良好地设计程序有非常大的帮助[1]. 首先说明一个概念:副 ...
- 基于OAS设计可扩展OpenAPI
前言 随着互联网行业的兴起,开发模式已逐步转换为微服务自治:小团队开发微服务,然后通过Restful接口相互调用.开发者们越来越渴望能够使用一种“官话”进行流畅的沟通,甚至实现多种编程语言系统的自动化 ...