并不对劲的CF1239B&C&D Programming Task in the Train to Catowice City
Posted xzyf
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了并不对劲的CF1239B&C&D Programming Task in the Train to Catowice City相关的知识,希望对你有一定的参考价值。
CF1239B The World Is Just a Programming Task
题目描述
定义一个括号序列s是优秀的,当且仅当它是以下几种情况的一种:
1.|s|=0
2.s=‘(’+t+‘)’,其中t是优秀的
3.s=t1+t2,其中t1、t2都是优秀的
一个括号序列的价值为将它看成一个循环串,从多少个位置切开,能切出循环串。
给出一个长度为(n)的括号序列,你可以交换其中两个位置的括号(这两个位置可以相等),问最大价值及方案。
输出任意一种方案均正确。(nleq 3 imes 10^5)
题解
代码
#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('
');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 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
%d %d",maxx,maxi,maxj);
return 0;
}
CF1239C Queue in the Train
题目描述
火车上有编号为1,2,...,(n)的(n)个人,第(i)个人会在第(t_i)秒醒来,他们醒来后都想接水,每个人接水都要花(p)分钟。
同时只会有一个人能接水,接水过程中不会被打断。其他去接水的人从去接水到接到水的过程中都会排队。
一个人醒来后,只有在发现编号不小于他的人中不存在“正在接水”或“正在排队”或“醒来了且没接到水”的人时,才会去接水。
人走到饮水机不需要时间。
求每个人接完水的时间。(nleq 10^5;q,tleq 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,mleq 10^6)
题解
如果只是选出(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('
');return ;}
if(x<0){putchar('-'),x=-x;}
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);putchar('
');
}
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
",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口胡的!!!
以上是关于并不对劲的CF1239B&C&D Programming Task in the Train to Catowice City的主要内容,如果未能解决你的问题,请参考以下文章
并不对劲的CF1245E&F:Cleaning Ladders