【codeforces】【比赛题解】#849 CF Round #431 (Div.2)
cf的比赛越来越有难度了……至少我做起来是这样。
先看看题目吧:点我。
这次比赛是北京时间21:35开始的,算是比较良心。
【A】奇数与结束
"奇数从哪里开始,又在哪里结束?梦想从何处起航,它们又是否会破灭呢?"
给定一个长度为n的序列。确定能不能将序列分成奇数个长度为奇数的非空字串,而且这其中每个子串以奇数开头,以奇数结尾。可以只分成一个(1也是奇数)。
输入
第一行一个正整数n,表示序列长度。
第二行n个整数,表示序列中的元素。
输出
输出"Yes"或"No"来表示能否做到把序列按要求分割。
样例输入1
5
1 0 1 5 1
样例输出1
Yes
样例输入2
4
3 9 9 3
样例输出2
No
题解
当时想了一个n²的DP,之后发现实在是太naive。
讲一下DP思路吧,用f1[i]表示能否将a[1...i]分割成奇数个奇数长度的子串,并且每个子串以奇数开头结尾,f2[i]表示能否分割成偶数个子串。
于是f1[i]=OR(f2[j] (a[j+1...i]长度为奇数并且以奇数开头结尾) ),f2[i]=OR(f1[j] (a[j+1...i]长度为奇数并且以奇数开头结尾) ).
特别的,f1[0]=false,f2[0]=true。
这种做法就可以过了,但是有更优秀的做法:
把序列分成奇数个奇数长度的序列,那么这个序列也是奇数长度的。偶数长度的直接No。
再考虑把序列分成两个以上的序列,那么最开始的序列的起始元素必须是奇数,最末尾的序列的结尾元素也必须是奇数。
这就对应了原序列的第一个与最后一个元素必须是奇数,而这时我们只分一段就好了。
就是说我们只需要判断n的奇偶,a[1]的奇偶和a[n]的奇偶就可以了。
程序:
#include <cstdio>
static const int MAXN = ; int n;
int a[MAXN]; int main()
{
scanf("%d", &n);
for (int i = ; i < n; ++i) scanf("%d", &a[i]); puts((n & ) && (a[] & ) && (a[n - ] & ) ? "Yes" : "No");
return ;
}
【B】
目前没做出来,调出来了再说自己的做法吧
先贴标程:
#include <bits/stdc++.h>
#define eps 1e-7
using namespace std;
int read()
{
int x=,f=;char ch=getchar();
while (ch<''||ch>''){if (ch=='-') f=-;ch=getchar();}
while (ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
int n,a[];
bool vis[];
bool check(double k,int b)
{
memset(vis,false,sizeof(vis));
int cnt=;
for (int i=;i<=n;i++)
{
if (a[i]-b==1LL*k*(i-))
{
vis[i]=true;
++cnt;
}
}
if (cnt==n) return false;
if (cnt==n-) return true;
int pos1=;
for (int i=;i<=n;i++)
if (!vis[i]&&pos1==) pos1=i;
for (int i=pos1+;i<=n;i++)
if (!vis[i])
{
if (fabs((double)(a[i]-a[pos1])/(i-pos1)-k)>eps) return false;
}
return true;
}
int main()
{
n=read();
for (int i=;i<=n;i++)
a[i]=read();
bool ans=false;
ans|=check(1.0*(a[]-a[]),a[]);
ans|=check(0.5*(a[]-a[]),a[]);
ans|=check(1.0*(a[]-a[]),a[]*-a[]);
if (ans) printf("Yes\n"); else printf("No\n");
return ;
}
【C】
题目都没看懂,真的很难受,这题挺难的。
标程:
#include <bits/stdc++.h> using namespace std; using ll = long long;
using ld = long double;
using D = double;
using uint = unsigned int;
template<typename T>
using pair2 = pair<T, T>; #ifdef WIN32
#define LLD "%I64d"
#else
#define LLD "%lld"
#endif #define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second int main()
{
int k;
scanf("%d", &k);
for (int i = ; i < ; i++)
{
int cnt = ;
while ((cnt + ) * cnt / <= k) cnt++;
k -= cnt * (cnt - ) / ;
for (int j = ; j < cnt; j++) printf("%c", 'a' + i);
}
return ;
}
"无论目标何在,无论遇见何人,让我们一同将这首歌传唱。"
在平面直角坐标系中,有一个长方形舞台,四角分别是(0,0),(0,h),(w,0),(w,h)。
可以看出在有任何人进入舞台之前,不会有任何碰撞发生。
在舞台的左边界和下边界站着一些舞者。分成两组:
①竖直:站在(xi,0)上,沿着y正方向前进(向上)。
②水平:站在(0,yi)上,沿着x正方向前进(向右)。
按照编舞指导,第i个舞者需要在前ti毫秒内站着不动,然后沿着指定方向以1单位/毫秒的速度前进,直到碰到舞台的边界为止。
当两个舞者碰撞时,她们会立刻改变各自的前进方向,然后继续沿着新的方向前进。
舞者们只要碰到了舞台的边界就会停止,请求出每个舞者最终停下的位置。
输入
第一行有三个数n,w,h。表示舞者数量,舞台的长宽。
接下来n行,每行三个数,gi,pi,ti,表示第i个舞者所在的组(gi=1:竖直组;gi=2:水平组),坐标位置(gi=1则pi=xi;gi=2则pi=yi)以及等待时间。
保证0<xi<w,0<yi<h。并保证没有两个舞者既在相同的组,还有相同的位置和等待时间。
输出
n行,每行两个数xi,yi。表示第i个舞者最终停在哪里。
样例输入1
8 10 8
1 1 10
1 4 13
1 7 1
1 8 2
2 2 0
2 5 14
2 6 0
2 6 1
样例输出1
4 8
10 5
8 8
10 6
10 2
1 8
7 8
10 6
样例输入2
3 2 3
1 1 2
2 1 1
1 1 5
样例输出2
1 3
2 1
1 3
数据范围及提示
1<=n<=100000,2<=w,h<=100000,1<=gi<=2,1<=pi<=99999,0<=ti<=100000。
对于样例数据1,这是对应的图:
对于样例数据2,没有舞者碰撞。
题解
很难的一题,不过我看来比C题简单……
注意到每个舞者出发后,每毫秒其坐标总是有一个加一,故(xi+yi)总是在增加。
而且我们发现,只有(xi+yi)相同的舞者才会碰撞。我们把(xi+yi)的值相同的舞者分在一起处理。
如何确定(xi+yi)的值呢??可以发现对于每个舞者,可以把(pi-ti)近似看做(xi+yi),(pi-ti)相同的舞者可能碰撞,而(pi-ti)不同的不可能碰撞。
我们对舞者按照(pi-ti)排序,处理出(pi-ti)相同的舞者。
对于(pi-ti)相同的舞者,我们如何处理呢?
试着把舞台斜过来看吧!让(0,0)在最下方,(w,h)在最顶端,(0,h)在左侧,(w,0)在最右侧。
这样,对于那些(pi-ti)相同的舞者,即出发后(xi+yi)相同的舞者们,她们在同一时间点必然处在同一水平线上。
并且每过一毫秒,她们向上走√2/2单位,向左或向右走√2/2单位。
这时候的碰撞要如何处理呢?
注意到在没有碰撞发生前,舞者从左到右的顺序是先是水平方向的舞者,坐标从大到小下来,然后是竖直方向的舞者,坐标从小到大往右走。
而所有碰撞都发生了之后呢??舞者的相对位置是不会改变的!原本在最左侧的舞者,仍然在左侧。舞者位置不会交换。
或者……这是另一种形式的交换了呢?注意到在水平方向坐标最大的舞者没有去到她本来应该去的位置,而是去了竖直方向第一个舞者应该去的位置。
是的,她们的位置交换了,但是这种交换很有规律,把舞者分成水平方向和竖直方向,那么水平方向的舞者按顺序要去到竖直方向的舞者按顺序应该去到的位置。依次推下来,就可以确定舞者最终的位置。我不太好解释这种方法的具体实现,先贴代码吧。
排序时要注意第一关键字是(pi-ti),第二关键字是先水平,后竖直,第三关键字是初始坐标,水平的从大到小,竖直的从小到大。
复杂度O(nlogn)
#include<cstdio>
#include<algorithm>
#include<cstring>
#define F(i,a,b) for(int i=a;i<=b;++i)
#define F2(i,a,b) for(int i=a;i<b;++i)
int n,w,h,g[],p[],t[],I[],Ans[],Ansg[];
inline bool cmp(int x,int y){
if(p[x]-t[x]<p[y]-t[y]) return ;
else if(p[x]-t[x]>p[y]-t[y]) return ;
else{
if(g[x]>g[y]) return ;
else if(g[x]<g[y]) return ;
else{
if(g[x]==) return p[x]<p[y];
else return p[x]>p[y];
}
}
}
int main(){
scanf("%d%d%d",&n,&w,&h);
F(i,,n) scanf("%d%d%d",g+i,p+i,t+i),I[i]=i;
std::sort(I+,I+n+,cmp);
I[n+]=; p[]=; t[]=-;
int hor=,ver=;
F(i,,n){
if(g[I[i]]==) ++ver; else ++hor;
if(p[I[i]]-t[I[i]]!=p[I[i+]]-t[I[i+]]){
int j=i-hor-ver+, k=i-ver+,l,o;
for(l=k,o=j;l<=i;++l,++o)
Ans[I[o]]=p[I[l]],Ansg[I[o]]=g[I[l]];
for(;o<=i;++o,++j)
Ans[I[o]]=p[I[j]],Ansg[I[o]]=g[I[j]];
ver=hor=;
}
}
F(i,,n) if(Ansg[i]==) printf("%d %d\n",Ans[i],h); else printf("%d %d\n",w,Ans[i]);
return ;
}
【E】
没看题,以后再补吧。
【codeforces】【比赛题解】#849 CF Round #431 (Div.2)的更多相关文章
- 竞赛题解 - CF Round #524 Div.2
CF Round #524 Div.2 - 竞赛题解 不容易CF有一场下午的比赛,开心的和一个神犇一起报了名 被虐爆--前两题水过去,第三题卡了好久,第四题毫无头绪QwQ Codeforces 传送门 ...
- CF Round #551 (Div. 2) D
CF Round #551 (Div. 2) D 链接 https://codeforces.com/contest/1153/problem/D 思路 不考虑赋值和贪心,考虑排名. 设\(dp_i\ ...
- CF Round #510 (Div. 2)
前言:没想到那么快就打了第二场,题目难度比CF Round #509 (Div. 2)这场要难些,不过我依旧菜,这场更是被\(D\)题卡了,最后\(C\)题都来不及敲了..最后才\(A\)了\(3\) ...
- CF Round #600 (Div 2) 解题报告(A~E)
CF Round #600 (Div 2) 解题报告(A~E) A:Single Push 采用差分的思想,让\(b-a=c\),然后观察\(c\)序列是不是一个满足要求的序列 #include< ...
- cf Round#273 Div.2
题目链接,点击一下 Round#273 Div.2 ================== problem A Initial Bet ================== 很简单,打了两三场的cf第一 ...
- 【codeforces】【比赛题解】#960 CF Round #474 (Div. 1 + Div. 2, combined)
终于打了一场CF,不知道为什么我会去打00:05的CF比赛…… 不管怎么样,这次打的很好!拿到了Div. 2选手中的第一名,成功上紫! 以后还要再接再厉! [A]Check the string 题意 ...
- 【codeforces】【比赛题解】#937 CF Round #467 (Div. 2)
没有参加,但是之后几天打了哦,第三场AK的CF比赛. CF大扫荡计划正在稳步进行. [A]Olympiad 题意: 给\(n\)个人颁奖,要满足: 至少有一个人拿奖. 如果得分为\(x\)的有奖,那么 ...
- 【codeforces】【比赛题解】#869 CF Round #439 (Div.2)
良心赛,虽然我迟了半小时233333. 比赛链接:#869. 呃,CF的比赛都是有背景的……上次是<哈利波特>,这次是<物语>…… [A]巧妙的替换 题意: Karen发现了石 ...
- 【codeforces】【比赛题解】#868 CF Round #438 (Div.1+Div.2)
这次是Div.1+Div.2,所以有7题. 因为时间较早,而且正好赶上训练,所以机房开黑做. 然而我们都只做了3题.:(. 链接. [A]声控解锁 题意: Arkady的宠物狗Mu-mu有一只手机.它 ...
随机推荐
- 第211天:git和github的区别和使用详解
一.git 1.什么是git 它是一个源代码管理工具,在一个项目中,凡是由开发人员编写的都算是源代码,源代码有必要管理起来,让源代码可以被追溯,主要记录每次变更了什么,谁主导这次变化.人为的维护比较麻 ...
- HDU4240_Route Redundancy
题目很简单.给一个有向图,求两点间的最大流量与任意一条路中的最大流量的比值. 最大流不说了,求出单条流量最大的路径可以用类似Spfa的方法来搞,保存到达当前点的最大流量,一直往下更新即可. 召唤代码君 ...
- PostgreSQL窗口函数
窗口函数允许在查询的SELECT列表和ORDER BY子句中使用. 如果有排序,要保证唯一,否则会有下面的错误: 修改方式是:保证唯一,修改方法如下:
- BZOJ5006 THUWC2017随机二分图(概率期望+状压dp)
下称0类为单边,1类为互生边,2类为互斥边.对于一种匹配方案,考虑其出现的概率*2n后对答案的贡献,初始为1,如果有互斥边显然变为0,否则每有一对互生边其贡献*2.于是有一个显然的dp,即设f[S1] ...
- 【刷题】BZOJ 1458 士兵占领
Description 有一个M * N的棋盘,有的格子是障碍.现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵.我们称这些士兵占领了整个棋盘当满足第i行至少放 ...
- 【刷题】洛谷 P1115 最大子段和
题目描述 给出一段序列,选出其中连续且非空的一段使得这段和最大. 输入输出格式 输入格式: 输入文件maxsum1.in的第一行是一个正整数N,表示了序列的长度. 第2行包含N个绝对值不大于10000 ...
- 【BZOJ4591】【Shoi2015】超能粒子炮
Description 传送门 Solution 记\(a=\lfloor\frac n p\rfloor\),\(b=n\%p\).我们尝试使用Lucas定理展开这些组合数,寻找公共部分.以下除 ...
- 【专题】字符串专题小结(AC自动机 + 后缀自动机)
AC自动机相关: $fail$树: $fail$树上以最长$border$关系形成父子关系,我们定一个节点对应的串为根到该节点的路径. 对于任意一个非根节点$x$,定$y = fa_{x}$,那$y$ ...
- keepalived使用nc命令检测udp端口
keepalived支持的健康检测方式有:HTTP_GET|SSL_GET.TCP_CHECK.SMTP_CHECK.MISC_CHECK. 由于keepalived自身并不支持udp检测,有TCP_ ...
- 遇到问题----mongodb-----mongorestore报错too many open files甚至mongo服务崩溃
之前运行mongorestore还原mongodb数据库一直都没问题,今天还原的时候 报错too many open files.而且mongo服务经常崩溃需要重启. 问题有两方面: 原因一 一个原因 ...