CF1239B The World Is Just a Programming Task

题目描述

定义一个括号序列s是优秀的,当且仅当它是以下几种情况的一种:

1.|s|=0

2.s=‘(’+t+‘)’,其中t是优秀的

3.s=t1+t2,其中t1、t2都是优秀的

一个括号序列的价值为将它看成一个循环串,从多少个位置切开,能切出循环串。

给出一个长度为\(n\)的括号序列,你可以交换其中两个位置的括号(这两个位置可以相等),问最大价值及方案。

输出任意一种方案均正确。\(n\leq 3\times 10^5\)

一行题解

“当前左括号数-右括号数”形成折线=>答案为折线中最低点个数=>发现交换配对的括号最赚=>维护贡献

题解

这个人讲得很清楚。

为了方便考虑,先特判左括号的个数是不是和右括号的个数不相等。

当左右括号相等时,一定存在一个位置切开循环串后得到优秀的括号序列。先随便找一个位置把它切开。

以位置为横坐标\(i\),以该位置及之前的括号序列中的左括号个数-右括号个数为纵坐标\(a_i\),建系,得到一条折线,最低点纵坐标为0。横坐标为0和为\(n\)的点纵坐标都是0。

发现从纵坐标为“所有纵坐标的最小值”的地方切开一定会得到优秀的序列。

考虑交换一对括号的作用。首先,交换相同方向的括号没有任何意义。

如果交换的是前面的右括号和后面的左括号,会使一段折线的坐标+2。因为横坐标为0和为\(n\)的点一定不会被包含,所以全局纵坐标最小值还是0,使一段折线坐标增加不会使最小值个数增加。

如果交换的是前面的左括号\(x\)和后面的右括号\(y\),会使一段折线的坐标-2。如果\(y\)不是\(x\)匹配右括号\(p_x\)的:当\(y<p_x\)时,\([x,y]\)中最低点在\(x\)处出现,随着\(y\)增加,和最低点纵坐标相同的点只会越来越多;当\(y>p_x\)时,考虑\(y=p_x+1\)时,因为\(y\)是右括号,\(a_y=a_{p_x}-1\),使\([x,p_x]\)中纵坐标等于\(x\)的点全部报废,这时就要前移\(x\)。

所以要求出每个括号匹配的括号,再用【随便什么数据结构】维护区间最小值和最小值的个数。

代码

#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define view(u,k) for(int k=fir[u];~k;k=nxt[k])
#define LL long long
#define maxn 300007
#define ls (u<<1)
#define rs (u<<1|1)
#define mi (l+r>>1)
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
void write(int x)
{
if(x==0){putchar('0'),putchar('\n');return;}
int f=0;char ch[20];
if(x<0)putchar('-'),x=-x;
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
putchar('\n');
return;
}
int mn[maxn<<2],num[maxn<<2];
int n,cnt0,maxx,maxi,maxj,tp,stk[maxn],pos[maxn],a[maxn],bac[maxn];
char s[maxn],t[maxn];
void work()
{
tp=0;int po=0;
rep(i,1,n)
{
if(s[i]=='(')stk[++tp]=i;
else{if(!tp)po=i;else tp--;}
}
if(po)
{
int cut=po+1;
int cntt=0;
rep(i,cut,n)t[++cntt]=s[i],bac[cntt]=i;
rep(i,1,cut-1)t[++cntt]=s[i],bac[cntt]=i;
}
else {rep(i,1,n)t[i]=s[i],bac[i]=i;}tp=0;
rep(i,1,n)
{
if(t[i]=='(')stk[++tp]=i;
else pos[i]=stk[tp],tp--;
}
return;
}
void pu(int u)
{
mn[u]=min(mn[ls],mn[rs]),num[u]=0;
if(mn[u]==mn[ls])num[u]=num[ls];
if(mn[u]==mn[rs])num[u]+=num[rs];
}
void build(int u,int l,int r)
{
if(l==r){mn[u]=a[l],num[u]=1;return;}
build(ls,l,mi),build(rs,mi+1,r),pu(u);
}
void ask(int u,int l,int r,int x,int y,int & ansmn,int & ansnum)
{
if(x<=l&&r<=y)
{
if(mn[u]==ansmn)ansnum+=num[u];
else if(mn[u]<ansmn)ansmn=mn[u],ansnum=num[u];
return;
}
if(x<=mi)ask(ls,l,mi,x,y,ansmn,ansnum);
if(y>mi)ask(rs,mi+1,r,x,y,ansmn,ansnum);
return;
}
int main()
{
scanf("%d%s",&n,s+1);
if(n&1){puts("0"),puts("1 1");return 0;}
rep(i,1,n)if(s[i]=='(')cnt0++;
if(cnt0!=n/2){puts("0"),puts("1 1");return 0;}
work();
rep(i,1,n){a[i]=a[i-1]+(t[i]=='('?1:-1);}
build(1,1,n);int num0=num[1];
maxx=num0,maxi=maxj=1;
rep(i,1,n)if(t[i]==')')
{
int aa=2147483647,bb=0,ansnow=0;ask(1,1,n,pos[i],i-1,aa,bb);
if(aa>2)continue;
if(aa==2)ansnow=num0+bb;
else ansnow=bb;
if(ansnow>maxx)maxx=ansnow,maxi=bac[pos[i]],maxj=bac[i];
}
printf("%d\n%d %d",maxx,maxi,maxj);
return 0;
}

CF1239C Queue in the Train

题目描述

火车上有编号为1,2,...,\(n\)的\(n\)个人,第\(i\)个人会在第\(t_i\)秒醒来,他们醒来后都想接水,每个人接水都要花\(p\)分钟。

同时只会有一个人能接水,接水过程中不会被打断。其他去接水的人从去接水到接到水的过程中都会排队。

一个人醒来后,只有在发现编号不小于他的人中不存在“正在接水”或“正在排队”或“醒来了且没接到水”的人时,才会去接水。

人走到饮水机不需要时间。

求每个人接完水的时间。\(n\leq 10^5;q,t\leq 10^9\)

题解

模拟这个过程。

把所有人以醒来时间为第一关键字,编号为第二关键字排序。

用队列维护正在排队的人。

用以编号为关键字的小根堆维护已经醒来但没接到水的人。

代码

#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define view(u,k) for(int k=fir[u];~k;k=nxt[k])
#define LL long long
#define maxn 100007
#define mp make_pair
#define pii pair<LL ,LL>
#define fi first
#define se second
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
void write(LL x)
{
if(x==0){putchar('0'),putchar(' ');return;}
int f=0;char ch[20];
if(x<0)putchar('-'),x=-x;
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
putchar(' ');
return;
}
int n,tr[maxn];
LL t[maxn];
LL p,ans[maxn],Q[maxn],hd=1,tl;
pii a[maxn];
priority_queue<int >q;
int lt(int x){return x&(-x);}
void add(int x,int k){for(;x<=n;x+=lt(x))tr[x]+=k;return;}
int ask(int x){int k=0;for(;x;x-=lt(x))k+=tr[x];return k;}
int main()
{
n=read(),p=read();
rep(i,1,n)t[i]=read(),a[i].fi=t[i],a[i].se=i;
sort(a+1,a+n+1);
LL start=0,tim=0,now=1;
rep(i,1,n)
{
while(now<=n&&a[now].fi<=tim)
{
if(a[now].se<start&&!ask(a[now].se))add(a[now].se,1),Q[++tl]=now;
else q.push(-a[now].se);now++;
}
if(hd<=tl)add(a[Q[hd]].se,-1),start=a[Q[hd]].se,hd++;
else if(!q.empty())start=-q.top(),q.pop();
else{start=a[now].se,tim=a[now].fi,now++;}
tim+=p,ans[start]=tim;
}
rep(i,1,n)write(ans[i]);
return 0;
}

CF1239D Catowice City

题目描述

有编号为\(1,2,...,n\)的\(n\)个人和编号为\(1,2,...,n\)的\(n\)只猫。第\(i\)号人认识第\(i\)号猫。

有\(m\)个形如\((x,y)\)的额外的条件,表示第\(x\)号人认识第\(y\)号猫。

问能否选出至少一个人、至少一只猫,使所有人不认识所有猫,并且人数+猫数=\(n\)。如果能,输出方案。

\(n,m\leq 10^6\)

一行题解

“互不认识”+“i号人认识i号猫”=>2-SAT=>只有“人->人”、“猫->猫”之间的边且同一对有边的人和有边的猫的边刚好相反=>只选一个无出边的强连通分量

题解

如果只是选出\(n\)个动物使选出来的所有人不认识所有猫,那么会发现第\(i\)号人和第\(i\)号猫中选且只选一个。

这样就可以2-SAT解决:点\(i\)表示选\(i\)号人,点\(i'\)表示选\(i\)号猫;对于条件\((x,y)\),需要建边\(x->y\)、\(y'->x\),表示选\(x\)号人后必须选\(y\)号人,选\(y\)号猫后必须选\(x\)号猫。

再考虑条件“至少一个人、至少一只猫”:发现这个图比较特殊,只有人之间的边和猫之间的边,并且人之间的边形成的拓扑图刚好和猫之间的边形成的拓扑图相反。这相当于每个人的强连通分量中的点的编号和对应的猫的强连通分量中点的编号相同。也就是说,可以选一个没有出边的强连通分量(记为S),强行选这个强连通分量的所有点,并且不选同一种动物的其它强连通分量的所有点。对于另一种动物,强行不选S中的所有点,选不在S中的所有点。发现这样构造一定符合2-SAT的性质。

当且仅当存在大小为\(n\)的强连通分量时,对于每一种动物都只有1个强连通分量,无法按上述方法构造。

代码

#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<set>
#include<stack>
#include<vector>
#include<queue>
#define LL long long
#define maxn 2000007
#define rep(i,x,y) for(int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(int i=(x);i>=(y);--i)
#define view(u,k) for(int k=fir[u];~k;k=nxt[k])
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
void write(int x)
{
int f=0;char ch[20];
if(x==0){putchar('0');putchar('\n');return ;}
if(x<0){putchar('-'),x=-x;}
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);putchar('\n');
}
int n,m,no,fir[maxn],nxt[maxn],v[maxn],cnte,dfn[maxn],low[maxn],ans[maxn],ins[maxn],stk[maxn],tp,tim,col[maxn],num;
void ade(int u1,int v1){v[cnte]=v1,nxt[cnte]=fir[u1],fir[u1]=cnte++;}
void tar(int u)
{
dfn[u]=low[u]=++tim,ins[u]=1,stk[++tp]=u;
view(u,k)
{
if(!dfn[v[k]])tar(v[k]),low[u]=min(low[u],low[v[k]]);
else if(ins[v[k]])low[u]=min(low[u],dfn[v[k]]);
}
if(dfn[u]==low[u])
{
num++;int cnt=0;
while(1)
{
cnt++;
col[stk[tp]]=num,ins[stk[tp]]=0;
if(stk[tp--]==u)break;
}
if(cnt==n)no=1;
}
}
int gx(int x,int f){return x+f*n;}
int main()
{
int t=read();
while(t--)
{
n=read(),m=read(),no=0;int li=n<<1;
rep(i,1,li)dfn[i]=0,fir[i]=-1;cnte=tim=num=0;
rep(i,1,m)
{
int x=read(),y=read();
if(x==y)continue;
ade(gx(x,0),gx(y,0)),ade(gx(y,1),gx(x,1));
}
int c[2],co=1;c[0]=c[1]=0;
rep(i,1,li)if(!dfn[i])tar(i);
if(no){puts("No");continue;}
rep(i,1,n)if(col[i]==1)co=0;
rep(i,1,n)
{
if(col[gx(i,0)]==col[gx(i,1)]){puts("No");no=1;break;}
if(col[gx(i,co)]==1)ans[i]=co,c[co]++;
else ans[i]=co^1,c[co^1]++;
}
if(no)continue;
puts("Yes");
printf("%d %d\n",c[0],c[1]);
rep(i,1,n)if(!ans[i])printf("%d ",i);puts("");
rep(i,1,n)if(ans[i])printf("%d ",i);puts("");
}
return 0;
}

一些感想

伟大的ysf口胡的!!!

The World Is Just a Shitful Task

并不对劲的CF1239B&C&D Programming Task in the Train to Catowice City的更多相关文章

  1. Codeforces Round #594 (Div. 1) D2. The World Is Just a Programming Task (Hard Version) 括号序列 思维

    D2. The World Is Just a Programming Task (Hard Version) This is a harder version of the problem. In ...

  2. [cf 1239 B] The World Is Just a Programming Task (Hard Version)

    题意: 给你一个长度为n的括号序列,你可以交换其中的两个元素,需要使该序列的n个循环移位中合法的括号序列个数尽量多. 输出最大的答案以及交换哪两个元素能够取到这个答案. $n\leq 3\times ...

  3. Codeforces 1239B. The World Is Just a Programming Task (Hard Version)

    传送门 这一题好妙啊 首先把括号序列转化成平面直角坐标系 $xOy$ 上的折线,初始时折线从坐标系原点 $(0,0)$ 出发 如果第 $i$ 个位置是 '(' 那么折线就往上走一步($y+1$),否则 ...

  4. codeforces#1248D2. The World Is Just a Programming Task(括号匹配转化为折线处理)

    题目链接: http://codeforces.com/contest/1248/problem/D2 题意: 可以执行一次字符交换的操作 使得操作后的字符串,循环移位并且成功匹配的方案最多 输出最多 ...

  5. CF The World Is Just a Programming Task (Easy Version)【分析·思维】

    题目传送门 题意: 给定一个括号序列,随意交换两个位置的括号之后,问有多少个不同长度的圈.关于圈的定义大概就是:将括号序列的后$k$个数放到括号序列的最前面,就是长度为$k$的圈.(看了好久题意emm ...

  6. Codeforces Round #594 (Div. 2) D1 - The World Is Just a Programming Task

    思路:枚举换的位置i,j 然后我们要先判断改序列能否完全匹配 如果可以 那我们就需要把差值最大的位置换过来 然后直接判断就行

  7. Codeforces Round #594 (Div. 2) D1 - The World Is Just a Programming Task (贪心)

    思路:枚举换的位置i,j 然后我们要先判断改序列能否完全匹配 如果可以 那我们就需要把差值最大的位置换过来 然后直接判断就行

  8. POJ1743 Musical Theme [后缀数组]

    Musical Theme Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 27539   Accepted: 9290 De ...

  9. The Swiss Army Knife of Data Structures … in C#

    "I worked up a full implementation as well but I decided that it was too complicated to post in ...

随机推荐

  1. CF258B

    CF258B 题意: 7个人在 $ [1,m] $ 区间内取数,求第一个人选的数的4和7的个数大于其他人的4和7个数总和的方案数. 解法: 要求输入的 $ m $ 可以很大,而且需要按位考虑每隔人的贡 ...

  2. 什么是跨平台性?原理是什么?JVM

    所谓跨平台性,是指java语言编写的程序,一次编译后,可以在多个系统平台上运行. 实现原理:Java程序是通过java虚拟机在系统平台上运行的,只要该系统可以安装相应的java虚拟机,该系统就可以运行 ...

  3. mysql 日期字符串互转

    字符串转日期select str_to_date('2008-4-2 15:3:28','%Y-%m-%d %H:%i:%s');select str_to_date('2008-08-09 08:9 ...

  4. Leetcode题目75.颜色分类(双指针-中等)

    题目描述: 给定一个包含红色.白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色.白色.蓝色顺序排列. 此题中,我们使用整数 0. 1 和 2 分别表示红色.白 ...

  5. iscc2018-Reverse-writeup

    RSA256 解析公钥 yafu质因数分解 p=325045504186436346209877301320131277983 q=3028255367440967415185462127611943 ...

  6. 2965 -- The Pilots Brothers' refrigerator

    The Pilots Brothers' refrigerator Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 27893 ...

  7. POJ 3083 -- Children of the Candy Corn(DFS+BFS)TLE

    POJ 3083 -- Children of the Candy Corn(DFS+BFS) 题意: 给定一个迷宫,S是起点,E是终点,#是墙不可走,.可以走 1)先输出左转优先时,从S到E的步数 ...

  8. linux内核中的subsys_initcall是干什么的?

    注意:使用的内核源码版本为5.1.3 1. subsys_initcall长什么样子? 它其实是个宏定义,定义如下: #define subsys_initcall(fn)     __define_ ...

  9. ubuntu 18.04 64bit下如何启动向日葵远程控制端软件?

    一. 背景 从向日葵官网下载了linux版向日葵远程控制端软件,解压后直接执行Sunlloginremote发现以下错误: jello@jello:~/sunlogin_remote_linux$ . ...

  10. 处理输入为非对角阵的Clustering by fast search and find of density peak代码

    Clustering by fast search and find of density peak. Alex Rodriguez, Alessandro Laio 是发表在Science上的一篇很 ...