Educational Codeforces Round 37

题面

题目详见CodeForces
先大概的写个翻译。。。

A

有一个长度为(n)的花园
(K)个水龙头,
假设水龙头的位置在(x)
(1s)(x)会被灌溉
(2s)([x-1,x+1])会被灌溉
(js)([x-j+1,x+j-1])会被灌溉
问这个花园在什么时候会被灌溉完

B

阅读理解题,我英语不好呀。。。
(n)个人要去喝茶
每个人有一个(l,r)
表示这个人会在第(ls)排队
如果同时间有多个人排队
按照编号排队
如果一个人到了队首,他就会花(1s)时间拿茶
如果一个人到了(rs)并且还没有拿到茶
他就会直接从队伍中离开
最后输出所有人的拿到茶的时间
如果从队伍中离开了输出(0)

C

一个长度为(n)的排列
如果一个位置(i)能够进行交换
那么,就可以交换(i)(i+1)位置上的数
回答能否通过若干次交换,
使得序列变为升序

D

(n)个水槽(神TM坦克)
都可以装无穷多的水
(i)个水槽里面有的水的体积为(ai)
有一个容量为(k)的水瓢
每次可以从一个水槽中拿走(min(ai,k))的水((ai)是剩余的水)
放到另外一个水槽中
问最后能否使得某个水槽中剩余容量为(V)
需要输出方案(不能超过(n+5)步)
输出的形式形如:(cnt x y)
表示从(x)中向(y)中用水瓢转移(cnt)次水

E

有一张(n)个点的图
给出(m)条不存在的边
其他的任意两点之间都存在边
最后询问联通块的个数以及每个联通块的大小

F

给定一个长度为(n)的序列
两种操作

1 l r 把l~r都变成d(ai)
2 l r 求l~r的和

其中d(x)是x的约数个数

G

多组询问
每次给定三个数(x p k)
求出大于(x)并且与(p)互质的第(k)个数


题解

A

傻逼题吧。。。
对于每一个水龙头就去更新所有的位置
最后输出最大值就好

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define MAX 500
inline int read()
{
    int x=0,t=1;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
int n,K,x[MAX];
int tt[MAX];
int main()
{
	int T=read();
	while(T--)
	{
		n=read();K=read();
		memset(tt,63,sizeof(tt));
		for(int i=1;i<=K;++i)
		{
			int x=read();
			for(int i=1;i<=n;++i)
				tt[i]=min(tt[i],abs(i-x));
		}
		int ans=0;
		for(int i=1;i<=n;++i)ans=max(ans,tt[i]);
		printf("%d
",ans+1);
	}
	return 0;
}

B

按照题目意思模拟就好
细节稍微注意一下

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define MAX 1500
inline int read()
{
    int x=0,t=1;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
struct Node{int l,r,id;}p[MAX];
bool operator <(Node a,Node b)
{
	if(a.l!=b.l)return a.l<b.l;
	else return a.id<b.id;
}
int n,ans[MAX];
int main()
{
	int T=read();
	while(T--)
	{
		n=read();
		for(int i=1;i<=n;++i)p[i].l=read(),p[i].r=read(),p[i].id=i;
		sort(&p[1],&p[n+1]);
		queue<Node> Q;while(!Q.empty())Q.pop();
		int pos=0;
		memset(ans,0,sizeof(ans));
		for(int i=1;i<=5000;++i)
		{
			while(pos<n&&p[pos+1].l==i)Q.push(p[++pos]);
			while(!Q.empty()&&Q.front().r<i)Q.pop();
			if(!Q.empty())ans[Q.front().id]=i,Q.pop();
		}
		for(int i=1;i<=n;++i)printf("%d ",ans[i]);puts("");
	}
	return 0;
}

C

每次交换可以拆开看
因为交换是可逆的
所以每次检查一下当前这个数字到他应该去的位置是否可行
检查是否可行,用前缀和检查一下(1)的个数就好

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define MAX 250000
inline int read()
{
    int x=0,t=1;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
int a[MAX],s[MAX],n,b[MAX];
char sw[MAX];
int main()
{
	n=read();
	for(int i=1;i<=n;++i)a[i]=read(),b[a[i]]=i;
	scanf("%s",sw+1);
	for(int i=1;i<n;++i)s[i]=s[i-1]+sw[i]-48;
	for(int i=1;i<=n;++i)
	{
		int r=b[i],l=i;
		if(r>l)swap(l,r);
		int ss=s[r-1]-s[l-1];
		if(ss!=r-l){puts("NO");return 0;}
	}
	puts("YES");
	return 0;
}

D

应该是个(dp)吧。。

我还不太会。。。
首先考虑所有的和是否能够满足条件
如果所有的和都小于要求,一定不可行
接下来考虑关于(K)的余数
做一个背包
算出哪些关于(K)的余数的体积是能够得到的
如果(V\%K)可行,在上面的的基础上一定能够构建出解
所以,先计算出选哪些水槽构建出(V\%K)
然后把这些水槽的水全部倒在一起
把剩下的水槽的水全部倒在一起
现在剩下的就是(K)的若干倍了
枚举之后看是倒进来还是倒出去就好了
记住,如果容量为(0)就不要倒
数据简直有毒,一定要各种判断。。。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 5010
inline int read()
{
    RG int x=0,t=1;RG char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
ll sum;
int n,K,V,a[MAX],b[MAX];
bool f[MAX][MAX];
int g[MAX][MAX],gg[MAX][MAX];
bool vis[MAX];
int main()
{
	n=read();K=read();V=read();
	for(int i=1;i<=n;++i)sum+=a[i]=read();
	if(sum<V){puts("NO");return 0;}
	for(int i=1;i<=n;++i)b[i]=a[i]%K;
	f[0][0]=1;
	memset(g,-1,sizeof(g));
	for(int i=1;i<=n;++i)
	{
		f[i][b[i]]=1;g[i][b[i]]=0;gg[i][b[i]]=1;
		for(int j=0;j<K;++j)
		{
			if(i!=1||j!=0)if(f[i-1][j])f[i][j]=1;
			if(f[i-1][j])
			{
				f[i][(j+b[i])%K]=1;
				g[i][(j+b[i])%K]=j;
			}
		}
	}
	if(V%K==0)
	{
		puts("YES");
		for(int i=2;i<=n;++i)if(a[i])printf("%d %d %d
",(a[i]-1)/K+1,i,1);
		if(V!=0)printf("%d %d %d
",V/K,1,2);
		return 0;
	}
	if(!f[n][V%K]){puts("NO");return 0;}
	puts("YES");
	int now=V%K,fst,ns;
	for(int i=n;i>=1;--i)
		if(g[i][now]!=-1)vis[i]=true,now=g[i][now],fst=i;
		else ns=i;
	for(int i=1;i<=n;++i)
		if(i!=fst)
		{
			if(!a[i])continue;
			if(vis[i])printf("%d %d %d
",(a[i]-1)/K+1,i,fst);
			else
			{
				if(i!=ns)printf("%d %d %d
",(a[i]-1)/K+1,i,ns);
				sum-=a[i];
			}
		}
	int nt=fst+1;if(nt==n+1)nt=fst-1;
	if(sum-V>=K)cout<<(sum-V)/K<<' '<<fst<<' '<<nt<<endl;
	else if(sum<V)
	{
		int tt=(V-sum)/K;
		cout<<tt<<' '<<ns<<' '<<fst<<endl;
	}
	return 0;
}

E

反图的遍历
每次不要枚举所有的点
只需要考虑所有还没有被经过的点就行了
这样子跑一边BFS就行

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 250000
inline int read()
{
    RG int x=0,t=1;RG char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
int n,m,tot,size[MAX];
set<int> a[MAX];
set<int> S;
int St[MAX],top=0;
void BFS(int SS)
{
	queue<int> Q;
	Q.push(SS);S.erase(SS);
	set<int>::iterator it;
	while(!Q.empty())
	{
		int u=Q.front();top=0;Q.pop();
		for(it=S.begin();it!=S.end();++it)
		{
			int v=*it;
			if(a[u].count(v))continue;
			St[++top]=v;
		}
		for(int i=1;i<=top;++i)
		{
			Q.push(St[i]);
			S.erase(St[i]);
			size[tot]++;
		}
	}
}
int main()
{
	n=read();m=read();
	for(int i=1;i<=m;++i)
	{
		int u=read(),v=read();
		a[u].insert(v);
		a[v].insert(u);
	}
	for(int i=1;i<=n;++i)S.insert(i);
	while(S.size())
	{
		++tot;
		size[tot]=1;
		BFS(*S.begin());
	}
	sort(&size[1],&size[tot+1]);
	printf("%d
",tot);
	for(int i=1;i<=tot;++i)printf("%d ",size[i]);puts("");
	return 0;
}

F

首先直接把约数个数筛出来(不用线性筛也行)
发现(d(1)=1,d(2)=2)
所以维护区间最大值
如果区间最大值(<=2)就不要更新
否则暴力更新整个区间

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define MAX 1000000
#define ll long long
#define lson (now<<1)
#define rson (now<<1|1)
inline int read()
{
    int x=0,t=1;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
bool zs[MAX+1];
int pri[MAX],tot;
int d[MAX+1],pn[MAX+1];
int n,m;
void pre()
{
	zs[1]=true;d[1]=1;
	for(int i=2;i<=MAX;++i)
	{
		if(!zs[i])pri[++tot]=i,d[i]=2,pn[i]=1;
		for(int j=1;j<=tot&&i*pri[j]<=MAX;++j)
		{
			zs[i*pri[j]]=true;
			if(i%pri[j])d[i*pri[j]]=d[i]*2,pn[i*pri[j]]=1;
			else{d[i*pri[j]]=d[i]/(pn[i]+1)*(pn[i]+2);pn[i*pri[j]]=pn[i]+1;break;}
		}
	}
}
struct Node
{
	int ma;
	ll s;
}t[MAX<<2];
void Build(int now,int l,int r)
{
	if(l==r){t[now].ma=t[now].s=read();return;}
	int mid=(l+r)>>1;
	Build(lson,l,mid);Build(rson,mid+1,r);
	t[now].s=t[lson].s+t[rson].s;
	t[now].ma=max(t[lson].ma,t[rson].ma);
}
void Modify(int now,int l,int r,int L,int R)
{
	if(t[now].ma<=2)return;
	if(l==r){t[now].s=t[now].ma=d[t[now].ma];return;}
	int mid=(l+r)>>1;
	if(L<=mid)Modify(lson,l,mid,L,R);
	if(R>mid)Modify(rson,mid+1,r,L,R);
	t[now].s=t[lson].s+t[rson].s;
	t[now].ma=max(t[lson].ma,t[rson].ma);
}
ll Query(int now,int l,int r,int L,int R)
{
	if(L<=l&&r<=R)return t[now].s;
	ll ret=0;
	int mid=(l+r)>>1;
	if(L<=mid)ret+=Query(lson,l,mid,L,R);
	if(R>mid)ret+=Query(rson,mid+1,r,L,R);
	return ret;
}
int main()
{
	n=read();m=read();pre();
	Build(1,1,n);
	while(m--)
	{
		int opt=read(),l=read(),r=read();
		if(opt==1)Modify(1,1,n,l,r);
		else printf("%I64d
",Query(1,1,n,l,r));
	}
	return 0;
}

G

先不考虑题目
怎么求(sum_{i=1}^n[gcd(i,p)=1])
这个做一个容斥就好
直接二分答案然后容斥计算个数
很简单的题。。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define MAX 10000000
#define ll long long
inline int read()
{
    int x=0,t=1;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
bool zs[MAX+1];
int pri[MAX+1],tot,mu[MAX+1],smu[MAX+1];
void pre()
{
	zs[1]=true;mu[1]=1;
	for(int i=2;i<=MAX;++i)
	{
		if(!zs[i])pri[++tot]=i,mu[i]=-1;
		for(int j=1;j<=tot&&i*pri[j]<=MAX;++j)
		{
			zs[i*pri[j]]=true;
			if(i%pri[j])mu[i*pri[j]]=-mu[i];
			else break;
		}
	}
	for(int i=1;i<=MAX;++i)smu[i]=smu[i-1]+mu[i];
}
int Count(int p,int n)
{
	int ret=0;
	for(int i=1;i*i<=p;++i)
	{
		if(p%i)continue;
		ret+=mu[i]*(n/i);
		if(p/i!=i)ret+=mu[p/i]*(n/(p/i));
	}
	return ret;
}
int main()
{
	int T=read();pre();
	while(T--)
	{
		int x=read(),p=read(),K=read();
		int ss=Count(p,x);
		int l=x+1,r=1e7,ans;
		while(l<=r)
		{
			int mid=(l+r)>>1;
			int sss=Count(p,mid);
			if(sss-ss>=K)ans=mid,r=mid-1;
			else l=mid+1;	
		}
		printf("%d
",ans);
	}
	return 0;
}

原文地址:https://www.cnblogs.com/cjyyb/p/8410033.html