Codeforces Global Round 28

打得有点烂,但还是抓住2024的尾巴上橙惹,记录一下赛时的想法和开心的心情w

image

A. Kevin and Combination Lock

给定一个整数x,一次操作可以将x赋值为x-33或者删去x中的“33”字串,询问能否在有限次操作内使x为0


删去字串不影响x%3和x%11的值,判断x能否被33整除即可


#include<iostream>
#include<cstdio>
#include<cstring>
#define I inline
using namespace std;
 
 
I void solve() {
	int x; cin>>x;
	if(x%33==0) {
		cout<<"YES"<<endl;
	} else {
		cout<<"NO"<<endl;
	}
}
int main()
{
	int T; cin>>T;
	while(T--) {
		solve();
	}
} 

B. Kevin and Permutation

构造排列n,使得n所有长度为k的subarray的最小值之和最小


一个数最多是k个subarray的最小值,在 k,2k,3k...mk 的位置放 1,2,3...m 即可


#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define I inline
using namespace std;
 
const int N = 100010;
int n,k,a[N];
 
I void solve() {
	cin>>n>>k;
	for(int i=1;i<=n;++i) a[i]=0;
	int hd=0;
	for(int i=k;i<=n;i+=k) {
		a[i]=++hd;
	}
	for(int i=1;i<=n;++i) {
		if(!a[i]) a[i]=++hd;
	}
	for(int i=1;i<=n;++i) cout<<a[i]<<' '; cout<<endl;
}
int main()
{
	int T; cin>>T;
	while(T--) {
		solve();
	}
} 

C. Kevin and Binary Strings

给定一个01串s,选出其中的两个子串s1,s2,使得子串异或结果最大。保证s首位为1,长度不超过5000


s1一定是s,找到s最高位0的位置p,则s2长度一定为p,可以暴力枚举判断。特判s全1的情况。


#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define I inline
using namespace std;
 
const int N = 5010;
int n,k,ans[N],now[N];
char a[N];
 
I void solve() {
	scanf("%s",a+1);
	n=strlen(a+1);
	cout<<1<<' '<<n<<' ';
	int fst=-1;
	for(int i=1;i<=n;++i) {
		if(a[i]=='0') {
			fst=i;
			break;
		}
	} 
	if(fst==-1) {
		cout<<1<<' '<<1<<endl;
		return ;
	}
	int len=n-fst+1,ansl=-1,ansr=-1;
	for(int i=1;i<=n;++i) ans[i]=a[i]-'0';
	
	for(int l=1;l+len-1<=n;++l) {
		
		for(int i=1;i<=n;++i) now[i]=a[i]-'0';
		
		int r=l+len-1;
	//	 cout<<l<<' '<<r<<endl;
		for(int i=l;i<=r;++i) {
			int ps=fst+i-l;
			now[ps]=((a[ps]-'0')^(a[i]-'0'));
		}
 
		bool big=0;
		for(int i=1;i<=n;++i) {
			if(now[i]==ans[i]) {
				continue ;
			} else if(now[i]<ans[i]) {
				break;
			} else {
				big=1;
				break;
			}
		}
		if(big) {
			for(int i=1;i<=n;++i) ans[i]=now[i];
			ansl=l; ansr=r;
		}
	}
	
	if(ansl==-1) {
		ansl=ansr=fst;
	}
	cout<<ansl<<' '<<ansr<<endl;
}
int main()
{
	int T; cin>>T;
	while(T--) {
		solve();
	}
} 

D. Kevin and Competition Memories

n个人m道题,人和题有rating,每个人可以做出rating小于等于自己的题。一场比赛k道题,共进行m/k场比赛。给出n,m以及rating(a,b)。求对k=1,2,3,...,m,在题目可以任意分配的情况下,第一个人rank之和的最小值。rank定义为做出更多题目的人数+1


考虑选择题目的策略,bia1bi 必选,a1bibi 中尽可能选大的。分配按照选择的顺序即可。


一开始想尽可能选小的浪费了一些时间,神秘..

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#define I inline
#define ll long long
using namespace std;
 
const int N = 300010;
int n,m,a[N],b[N],fst[N],va,dn;
 
I void solve() {
	cin>>n>>m; dn=0;
	for(int i=1;i<=n;++i) cin>>a[i];
	for(int i=1;i<=m;++i) cin>>b[i],fst[i]=0;
	va=a[1];
	for(int i=1;i<=m;++i) {
		if(b[i]<=va) dn++;
	}
	sort(a+1,a+1+n);
	sort(b+1,b+1+m);
	
	int j=1;
	for(int i=1;i<=m;++i) {
		while(j!=n+1&&a[j]<b[i]) {
			j++;
		}
		fst[i]=j;
	}
	
//	cout<<"b"<<endl;
//	for(int i=1;i<=n;++i) cout<<a[i]<<' '; cout<<endl;
//	for(int i=1;i<=m;++i) cout<<b[i]<<' '; cout<<endl;
//	for(int i=1;i<=m;++i) cout<<fst[i]<<' '; cout<<endl;
	
	ll ans=0;
	for(int i=1;i<=m;++i) {
		ans=0;
		int cnt=m/i;
		if(cnt*i<=dn) {
			continue;
		}
		ans=dn/i;
		int rev=dn%i,rc=cnt-dn/i,ps=m;
		if(rev!=0) {
			ps=ps-(i-rev)+1;
			ans+=n-fst[ps]+2;
			rc--; ps--;
		}
		
		for(int j=1;j<=rc;++j) {
			ps=ps-i+1;
			ans+=n-fst[ps]+2;
			ps--;
		}
		cout<<ans<<' ';
	} cout<<endl;
	
}
int main()
{
	int T; cin>>T;
	while(T--) {
		solve();
	}
} 

E. Kevin and Bipartite Graph

给出一个二分图,左部点 2n 个,右部点 m 个,任意左部点和右部点有边。用 n 种颜色对所有边染色,不能出现同色环。判断是否可行并构造方案。


注意到,一种颜色最多染 2n+m1 条边,否则一定成环(边数大于等于点数)。

共有 2mn 条边,可被染色的边共有n(2n+m1) 条,当 2mn>n(2n+m1) ,即 2nm 时无解。

对于m<2n ,尝试构造 m=2n1 的情况,并通过删除右部点得到任意m的情况。

对于解存在性的讨论其实提供了一种构造的思路:考虑每种颜色,在图中各染 m+2n1 条边。一种构造方法是使得m=2n。对于颜色 i ,左部点 j 向右部点 (i+j1)mod(2n)+1(i+j)mod(2n)+1 连边,再删除右部点中的任意一个点


花了好多时间...一开始想偏惹...


#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#define I inline
#define ll long long
using namespace std;
 
const int N = 300010;
int n,m,a[N],b[N],fst[N],va,dn;
int ans[2010][2010];
 
I void trans(int x,int col) {
	for(int i=1;i<=n*2;++i) {
		int nxt=i+x;
		if(nxt>(n*2)) nxt-=n*2;
		ans[i][nxt]=col;
	}
}
I void solve() {
	cin>>n>>m;
	if(m>=2*n) {
		cout<<"NO"<<endl;
		return ;
	}
	cout<<"YES"<<endl;
	int c=0;
	for(int i=1;i<=n*2;i+=2) {
		int j=i+1;
		trans(i-1,++c);
		trans(j-1,c);
	}
	for(int i=1;i<=n*2;++i) {
		for(int j=1;j<=m;++j) {
			cout<<ans[i][j]<<' ';
		} cout<<endl;
	}
}
int main()
{
	int T; cin>>T;
	while(T--) {
		solve();
	}
} 

F. Kevin and Math Class

给定n和长度为n的数组a,b,定义一次操作为选择区间 [l,r] ,将 lirai 变为 xai,这里 xlirbi 的最小值。


Global Round 偶遇神秘F,奇怪操作强如怪物,拼尽全力无法战胜。

赛时思路

第一眼感觉很不可做,但胡出做法的用时比e短得多。然而没调出来,正确性未知。

感性理解,大胆猜测,操作进行的顺序对结果无影响。考虑每个bi作为x的区间 [li,ri] ,在i处做完操作[li,ri] 会和 [li1,ri1][li+1,ri+1] 合并,这样一定不劣。讨论区间最大值计算贡献以及合并的方式。可以用线段树维护这个过程。细节很多。

赛时代码 WA on pretest 2

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#define I inline
#define int long long
#define lson (k<<1)
#define rson (k<<1|1)
#define mid (l+r>>1) 
using namespace std;
 
const int N = 200010;
struct node {
	int mx;
};
int a[N],b[N],Lp[N],Lv[N],Rp[N],Rv[N],f[N][21],lg[N],pw[22];
int n;
struct Seg {
	node tr[N<<2];
	I void update(int k) {
		tr[k].mx=max(tr[lson].mx,tr[rson].mx);
	}
	int query(int l,int r,int nl,int nr,int k) {// cout<<nl<<' '<<nr<<endl;
		if(l>=nl&&r<=nr) return tr[k].mx;
		int ret=0;
		if(nl<=mid) ret=max(ret,query(l,mid,nl,nr,lson));
		if(nr>mid) ret=max(ret,query(mid+1,r,nl,nr,rson));
		return ret;
	}
	void build(int l,int r,int k) {
		tr[k].mx=0;
		if(l==r) {
			tr[k].mx=a[l];
			return ;
		}
		build(l,mid,lson);
		build(mid+1,r,rson);
		update(k);
	}
}seg;
map<int,int > mp;
I int gans(int na,int x,int tov) {
	int c=0;
	while(1) { //cout<<"Sa";
		if(tov>=na) return c;
		c++;
		na=na/x+(na%x!=0);
	}
}
bool fir[N];
int qmax(int l,int r) {
	int len=lg[r-l+1];
	return max(f[l][len],f[r-pw[len]+1][len]);
}
I void solve() {
	cin>>n;
	for(int i=1;i<=n;++i) cin>>a[i],fir[i]=0; mp.clear();
	for(int i=1;i<=n;++i) cin>>b[i];
	for(int i=1;i<=n;++i) f[i][0]=a[i];
	for(int i=1;i<=20;++i) {
		for(int j=1;j+pw[i]-1<=n;++j) {
			f[j][i]=max(f[j][i-1],f[j+pw[i-1]][i-1]);
		}
	} 
	int mx=0;
	for(int i=1;i<=n;++i) {
		if(mp[a[i]]==0) {
			fir[i]=1;
		} else fir[i]=0;
		mp[a[i]]=1;
		if(mx<=a[i]) {
			Lp[i]=0;
			mx=a[i];
			continue;
		}
		int l=1,r=i-1,ps=-1;
		while(l<=r) {
			int M=l+r>>1;
			if(qmax(M,i-1)>a[i]) {
				ps=M;
				l=M+1;
			} else r=M-1;
		}
		Lp[i]=ps;
		mx=max(mx,a[i]);
	}
	mx=0;
	for(int i=n;i>=1;--i) {
		if(mx<=a[i]) {
			Rp[i]=0;
			mx=a[i];
			continue;
		}
		int l=i+1,r=n,ps=-1;
		while(l<=r) {
			int M=l+r>>1;
			if(qmax(i+1,M)>a[i]) {
				ps=M;
				r=M-1;
			} else l=M+1;
		}
		Rp[i]=ps;
		mx=max(mx,a[i]);
	}
	for(int i=1;i<=n;++i) {
		if(!Lp[i]) Lp[i]=0;
		if(!Rp[i]) Rp[i]=n+1;
	}
	int ans=0;
	seg.build(1,n,1);// cout<<"sa";
	int mn=1e18;
	for(int i=1;i<=n;++i) mn=min(mn,b[i]);
//	for(int i=1;i<=n;++i) cout<<Lp[i]<<' '<<Rp[i]<<endl;
	for(int i=1;i<=n;++i) { //<<endl;
		if(!fir[i]) continue;
		if(!Lp[i]&&Rp[i]==n+1) {
		//	cout<<a[i]<<' '<<b[i]<<' '<<1<<endl; 
			ans+=gans(a[i],b[i],1);
		} else {
		//	if(a[Lp[i]]==a[i]&&Lp[i]!=0) continue;
			int tov=1ll*1e18,nv=seg.query(1,n,Lp[i]+1,Rp[i]-1,1);
			if(Lp[i]) tov=min(tov,seg.query(1,n,Lp[Lp[i]]+1,Rp[Lp[i]]-1,1));
			if(Rp[i]!=n+1) tov=min(tov,seg.query(1,n,Lp[Rp[i]]+1,Rp[Rp[i]]-1,1));
			ans+=gans(nv,b[i],tov);
		} 
	}
	cout<<ans+1<<endl;
}
signed main()
{
	{
		lg[1]=0;
		for(int i=2;i<=200000;++i) lg[i]=lg[i/2]+1;
		pw[0]=1;
		for(int i=1;i<=20;++i) pw[i]=pw[i-1]<<1;
	}
	int T; cin>>T;
	while(T--) {
		solve();
	}	
}

D调得有点慢,E一开始想到路径覆盖之类的东西了。还有11天就要Good Bye 2024了。想起Hello 2024的时候C没出,现在已经能连着出E了],令人感叹...

posted @   Kur0n1ko  阅读(53)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示