zoukankan      html  css  js  c++  java
  • 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;
    }
    
    
  • 相关阅读:
    最实用的深度学习教程 Practical Deep Learning For Coders (Kaggle 冠军 Jeremy Howard 亲授)
    线性代数的本质与几何意义 01. 向量是什么?(3blue1brown 咪博士 图文注解版)
    【小蜜蜂老师主讲】基于STM32CubeMX的嵌入式开发基础教程
    【STM32专题教程】STM32CubeMX的安装与快速入门
    【技能大赛真题】2019年物联网国赛任务三题1-无线通信系统
    【CC2530强化实训03】定时器间隔定时实现按键长按与短按
    【CC2530强化实训04】定时器间隔定时实现按键N连击
    【CC2530强化实训02】普通延时函数实现按键的长按与短按
    【CC2530强化实训01】普通延时函数实现按键的长按与短按
    【蓝桥杯单片机12】实时时钟DS1302的基本操作
  • 原文地址:https://www.cnblogs.com/cjyyb/p/8410033.html
Copyright © 2011-2022 走看看