Codeforces Round #637 - Thanks, Ivan Belonogov! Solution

A A A

int T,n,a,b,c,d,m,st,ed,l,r;

int main() {
	qr(T); for(int t=1;t<=T;t++) {
		qr(n); qr(a); qr(b); qr(c); qr(d);
		st=a-b; ed=a+b; l=c-d; r=c+d; 
		if(st*n>r||ed*n<l) {puts("NO"); continue;}
		puts("YES");
	}
	
	return 0;
}

B B B

前缀和

int T,k,n,a[N],s[N],ans,pos;

int main() {
	qr(T); while(T--) {
		 qr(n);qr(k);
		for(int i=1;i<=n;i++) 
			qr(a[i]);
		for(int i=2;i<n;i++) {
			if(a[i-1]<a[i]&&a[i]>a[i+1]) s[i]=1;
			else s[i]=0;
			s[i]+=s[i-1];
		}
		pos=1;ans=0;
		for(int i=1;i+k-1<=n;i++) 
			if(ans<s[i+k-2]-s[i]) ans=s[i+k-2]-s[i],pos=i;
		pr1(ans+1); pr2(pos);
	}
	return 0;
}

C C C

一个合法的排列类似:

5 3 4 1 2

从1开始往右扫直到碰到第n+1个位置或者已经访问过的位置,此时跳到应该扫描的位置并重复操作.

如上例:扫描1 2,扫描3 4,扫描5

如果不能扫描完全则输出-1.

int T,n,a[N],ans,vis[N],num,p[N],now;

int main() {
	qr(T); while(T--) {
		qr(n); vis[n+1]=++num;
		for(int i=1;i<=n;i++) qr(a[i]),p[a[i]]=i;
		now=p[1]-1; ans=1;
		for(int i=1;i<=n;i++)
			if(p[i]==now+1) vis[p[i]]=num,now++;
			else if(vis[now+1]==num) vis[now=p[i]]=num;
			else {ans=0; break;}
		puts(ans?"YES":"NO");
	}
	return 0;
}

D D D

考察简单的DP+状态压缩.

f [ i ] [ j ] f[i][j] f[i][j]表示 [ i , n ] 选 择 j 个 额 外 的 棒 子 [i,n]选择j个额外的棒子 [i,n]j最大数的当前 i i i位选择的数.

保障最大的措施是从后往前枚举和数字从小到大枚举.

int n,m,f[N][N],pre[N][N],a[N],cnt[N],num[11]={119,18,93,91,58,107,111,82,127,123,};
char s[N];

int g(char *s) {
	int y=0;
	for(int i=0;i<7;i++) y=y*2+(s[i]-'0');
	return y;
}

bool pd(int x,int y) {return ((x&num[y])==x);}//x->y 

int main() {
	for(int i=1;i<=(1<<7);i++)cnt[i]=cnt[i&(i-1)]+1;
	qr(n); qr(m); memset(f,-1,sizeof f);
	for(int i=1;i<=n;i++) {
		scanf("%s",s);
		a[i]=g(s);
	}
	for(int i=0,j;i<=9;i++) if(pd(a[n],i)) f[n][cnt[num[i]^a[n]]]=i;
	for(int i=n-1;i>0;i--) {
		for(int j=0,k;j<=9;j++)
			if(pd(a[i],j)) {
				k=cnt[num[j]^a[i]];
				for(int x=k;x<=m;x++)
					if(f[i+1][x-k]!=-1) {
						f[i][x]=j;
						pre[i][x]=x-k;
					}
			}
	}
	if(f[1][m]==-1) puts("-1");
	else {
		int x=m;
		for(int i=1;i<=n;i++)
			qw(f[i][x]),x=pre[i][x];
	}
	return 0;
}

E E E

m m m轮搜索即可.
复杂度大概为 O ( m g ) O(mg) O(mg)

#include<bits/stdc++.h>
#define pb push_back
using namespace std;
const int N=10010,G=1010;
int x[N],n,m,r,g,ans=2e9;
bool v[N][G];
vector<int> q[N];
void dfs(int now,int u,int t) {
	if(u<1||u>m||t<0||v[u][t]) return ;
	v[u][t]=1;
	if(u==m) ans=min(ans,now*(g+r)+g-t);
	if(!t) q[now+1].pb(u);
	else {
		dfs(now,u-1,t-(x[u]-x[u-1]));
		dfs(now,u+1,t-(x[u+1]-x[u]));
	}
}
void qr(int &x) {scanf("%d",&x);}
int main() {
	qr(n); qr(m);
	for(int i=1;i<=m;i++) qr(x[i]);
	qr(g); qr(r);
	sort(x+1,x+m+1); q[0].pb(1);
	for(int i=0;i<=m;i++) {
		for(int j:q[i]) dfs(i,j,g);
		if(ans!=2e9) {printf("%d\n",ans); exit(0);}
	}
	puts("-1");
	return 0;
}

F F F

orz mayaohua

#include<cstdio>
#include<vector>
#define pi pair<int,int>
using namespace std;
const int N=1e6+10;

vector<int>e[N];
int n,m,cnt,deg[N];
pi ans[N*3];

void dfs(int x,int t,int f) {
	int fir=t;
	ans[++cnt]=pi(x,t);
	for(int y:e[x]) if(y^f) {
		if(t==m) {
			t=m-deg[x];
			ans[++cnt]=pi(x,t);
		}
		dfs(y,++t,x);
		ans[++cnt]=pi(x,t);
	}
	if(t!=fir-1&&x>1) ans[++cnt]=pi(x,fir-1);//保障回溯时为fir-1 
}

void add(int x,int y) {deg[x]++; e[x].push_back(y);}

int main() {
	scanf("%d",&n);
	for(int i=1,x,y;i<n;i++)
		scanf("%d %d",&x,&y),add(x,y),add(y,x);
	for(int i=1;i<=n;i++) m=max(m,deg[i]);//最大的t值显然为maxdeg 
	dfs(1,0,0);printf("%d\n",cnt);
	for(int i=1;i<=cnt;i++) printf("%d %d\n",ans[i].first,ans[i].second);
	return 0;
}

G G G

暂无题解

H H H

这是个有修改的问题,不难想到线段树.
同时,又有连续段的快速匹配,不难想到Hash.

显然如果一个串中有一个子段是类似"2 -1".这样整个串都不合法.
所以我们线段树节点要维护3个量(左边右括号,右边左括号,是否整段不合法).
这样我们就可以忽略中间匹配消去的部分,同时快速合并.

合并的时候细节较多,要非常注意.

复杂度 O ( n log ⁡ 2 n ) O(n\log^2 n) O(nlog2n)

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define gc getchar()
#define lc (x<<1)
#define rc (x<<1|1)
using namespace std;
typedef long long ll;
const int N=1e5+10;
const int b1=233,m1=1e9+9;
const int b2=131,m2=998244353;

void qr(int &x) {
	char c=gc; x=0; int f=1;
	while(!isdigit(c)){if(c=='-')f=-1; c=gc;}
	while(isdigit(c))x=x*10+c-'0',c=gc;
	x*=f;
}

int p1[N],p2[N];
//Hash
struct str {
	int len,h1,h2;
	str(int x=0) {h1=h2=x; len=x>0;}
	inline str operator +(str b) const {
		str c; c.len=len+b.len;
		c.h1=((ll)h1*p1[b.len]+b.h1)%m1;
		c.h2=((ll)h2*p2[b.len]+b.h2)%m2;
		return c;
	}
	inline str operator -(str b) const {
		str c; c.len=len-b.len;	
		c.h1=(h1-(ll)b.h1*p1[c.len]%m1+m1)%m1;
		c.h2=(h2-(ll)b.h2*p2[c.len]%m2+m2)%m2;
		return c;
	}
	bool operator ==(str b) const {return len==b.len&&h1==b.h1&&h2==b.h2;}
}L,R;

//线段树 
struct node {
	str l,r; bool flag;//和左/右匹配的右/左括号的hash.是否无效. 
	node(){l=r=str();flag=0;}
}t[N<<2];

void queryr(int x,int l,int r,int len) {//找x右侧的len个未匹配左括号
	while(R.len^len) {
		if(l==r) {R=R+t[x].r; return ;}
		int mid=(l+r)>>1;
		if(R.len+t[rc].r.len-L.len>=len||t[rc].flag) x=rc,l=mid+1;
		else {
			if(t[rc].r.len>L.len) R=R+(t[rc].r-L),L=str();
			else L=L-t[rc].r;
			L=t[rc].l+L;
			x=lc; r=mid;
		}
	}
}

void queryl(int x,int l,int r,int len) {//找x左侧的len个未匹配的右括号 
	while(L.len^len) {
		if(l==r) {L=L+t[x].l; return ;}
		int mid=(l+r)>>1;
		if(L.len+t[lc].l.len-R.len>=len||t[lc].flag) x=lc,r=mid;
		else {
			if(t[lc].l.len<R.len) R=R-t[lc].l;
			else L=L+(t[lc].l-R),R=str();
			R=t[lc].r+R;
			x=rc;l=mid+1;
		}
	}
}

node pushup(int x,int l,int r,node a,node b) {
	node c; c.flag=a.flag|b.flag;
	if(c.flag) return c;
	if(!a.r.len) {c.l=a.l+b.l; c.r=b.r; return c;}
	if(!b.l.len) {c.r=b.r+a.r; c.l=a.l; return c;}
	L=R=str();
	int mid=(l+r)>>1;
	if(a.r.len<b.l.len) {
		queryl(rc,mid+1,r,a.r.len);
		if(a.r==L) c.l=a.l+(b.l-a.r),c.r=b.r;
		else c.flag=1;
	}
	else {
		queryr(lc,l,mid,b.l.len);
		if(b.l==R) c.r=b.r+(a.r-b.l),c.l=a.l;
		else c.flag=1;
	}
	return c;
}

void pushup_all(int x,int l,int r) {t[x]=pushup(x,l,r,t[lc],t[rc]);}

void change(int x,int l,int r,int pos,int d) {
	if(l==r) {
		t[x]=node();
		if(d>0) t[x].r=str(d);
		else t[x].l=str(-d);
		return ;
	}
	int mid=(l+r)>>1;
	if(pos<=mid) change(lc,l,mid,pos,d);
	else change(rc,mid+1,r,pos,d);
	pushup_all(x,l,r);
}

node query(int x,int l,int r,int L,int R) {
	if(L==l&&r==R) return t[x];
	int mid=(l+r)>>1;
	if(R<=mid) return query(lc,l,mid,L,R);
	else if(mid<L) return query(rc,mid+1,r,L,R);
	else {
		node t1=query(lc,l,mid,L,mid);
		node t2=query(rc,mid+1,r,mid+1,R);
		return pushup(x,l,r,t1,t2);
	}
}

int n,m,a[N];

void bt(int x,int l,int r) {
	if(l==r) {
		int d=a[l];
		if(d>0) t[x].r=str(d);
		else t[x].l=str(-d);
		return ;
	}
	int mid=(l+r)>>1;
	bt(lc,l,mid);
	bt(rc,mid+1,r);
	pushup_all(x,l,r);
}

int main() {
	qr(n); qr(m);
	p1[0]=1;for(int i=1;i<=n;i++) p1[i]=(ll)p1[i-1]*b1%m1;
	p2[0]=1;for(int i=1;i<=n;i++) p2[i]=(ll)p2[i-1]*b2%m2;
	for(int i=1;i<=n;i++) qr(a[i]);
	bt(1,1,n); qr(m);
	while(m--) {
		int op,x,y; qr(op); qr(x); qr(y);
		if(op==1) change(1,1,n,x,y);
		else {
			node res=query(1,1,n,x,y);
			if(res.flag||res.l.len||res.r.len) puts("No");
			else puts("Yes");
		}
	}
	return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值