Codeforces Round #474 (Div. 1 + Div. 2)

题目链接:Codeforces Round #474 (Div. 1 + Div. 2)


A:直接枚举每种情况即可,判断有没有其他字母,判断每个字母当中有没有其他字母,判断一下顺序就好了。

AC代码:

#include<bits/stdc++.h>
using namespace std;
string str; map<char,int> mp,pos,pre; set<int> st;
int main(){
    cin>>str; str=" "+str;
    for(int i=1;i<str.size();i++){
        mp[str[i]]++,pos[str[i]]=i,st.insert(str[i]);
        if(!pre[str[i]])    pre[str[i]]=i;
    }    
    if(!mp['a']||!mp['b']||!mp['c'])    return puts("NO"),0;
    if(st.size()>=4) return puts("NO"),0;
    if(pos['a']>pos['b']||pos['a']>pos['c']||pos['b']>pos['c'])     return puts("NO"),0;
    if(mp['c']!=mp['b']&&mp['c']!=mp['a'])  return puts("NO"),0;
    if(pos['a']-pre['a']!=mp['a']-1)    return puts("NO"),0;
    if(pos['b']-pre['b']!=mp['b']-1)    return puts("NO"),0;
    if(pos['c']-pre['c']!=mp['c']-1)    return puts("NO"),0;
    puts("YES");
    return 0;
}

B:其实我们可以知道对于a改变k1次,对b改变k2次,我们可以看做是对a改变k1+k2次,所以每次暴力找一个最大差值,贪心即可。

AC代码:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e3+10;
int n,k1,k2,a[N],b[N],m,res;
signed main(){
	cin>>n>>k1>>k2; m=k1+k2;
	for(int i=1;i<=n;i++)	cin>>a[i];
	for(int i=1;i<=n;i++)	cin>>b[i];
	while(m--){
		int mx=-1e9,id=1;
		for(int i=1;i<=n;i++){
			if(abs(a[i]-b[i])>mx)	id=i,mx=abs(a[i]-b[i]);
		}
		if(a[id]>=b[id])	a[id]--;	else	a[id]++;
	}
	for(int i=1;i<=n;i++)	res+=(a[i]-b[i])*(a[i]-b[i]);
	cout<<res<<endl;
	return 0;
}

C:我们每次用很大的相同的数字去尽量接近当前的x,(也就是用2的次幂),然后x再减去当前的构成方案数,一直循环直到x很小的时候就暴力填单个数字即可。

AC代码:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define int long long
using namespace std;
int x,d,m,base=1e16; vector<int> res;
int qmi(int a,int b){
	int res=1;	while(b){if(b&1) res=res*a; a=a*a; b>>=1;}	return res;
}
signed main(){
	cin>>x>>d;
	while(x>3000){
		for(int i=1;;i++){
			if(qmi(2,i+1)-1>x){m=i; break;}
		}	x-=qmi(2,m); x++;
		for(int i=1;i<=m;i++)	res.push_back(base);
		base-=1e12;
	}
	while(x--){base-=1e11; res.push_back(base);}
	cout<<res.size()<<endl;
	for(int i=0;i<res.size();i++)	cout<<res[i]<<' ';
	return 0;
}

D:因为是一个完全二叉树,所以树高是log级别的。然后暴力判断每一层右移了多少次(把左移看做右移)。每次看当前数字的上一个数字应该是多少,计算一下即可。其实可以预处理 2的次幂,更快。

AC代码:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
int q,cnt[70];
inline int get(int x){
	int res=0;	while(x){x>>=1LL; res++;}	return res;
}
int qmi(int a,int b){
	int res=1; while(b){if(b&1LL) res=res*a; a=a*a; b>>=1LL;} return res;
}
signed main(){
	cin>>q;
	while(q--){
		int op,x,y,k;	scanf("%lld %lld",&op,&x); y=x; x=get(x);
		if(op==1){
			scanf("%lld",&k); if(k<0) k+=qmi(2,x-1);
			cnt[x]=(cnt[x]+k)%qmi(2,x-1);
		}
		else if(op==2){
			scanf("%lld",&k); if(k<0)	k+=qmi(2,x-1);
			for(int i=x;i<=64;i++,k<<=1LL)	cnt[i]=(cnt[i]+k)%qmi(2,i-1);
		}else{
			while(y){
				int h=get(y),num=qmi(2,h-1);
				printf("%lld ",y);
				y=y+cnt[h]; y>>=1LL; 
				if(num!=1)	y=(y-cnt[h-1]+num/2)%(num/2)+(num/2);
			}
			puts("");
		}
	}
	return 0;
}

F:我们有一种很明显的DP,我们按照输入的顺序,建立N颗权值线段树,比如 A->B权值为C的边,我们每次从线段树A当中找权值小于C的最大值,加上一就是这个节点可能更新的最大值。但是N颗权值线段树空间太大了,所以我们动态开点即可。

AC代码:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=1e5+10;
int n,m,res;
int rt[N],lc[N*20],rc[N*20],mx[N*20],cnt;
void change(int &p,int l,int r,int x,int v){
	if(!p)	p=++cnt;
	if(l==r){mx[p]=max(mx[p],v); return ;}
	int mid=l+r>>1;
	if(x<=mid)	change(lc[p],l,mid,x,v);
	else	change(rc[p],mid+1,r,x,v);
	mx[p]=max(mx[lc[p]],mx[rc[p]]);
}
int ask(int p,int l,int r,int ql,int qr){
	if(!p||l>r)	return 0;
	if(l==ql&&r==qr)	return mx[p];
	int mid=l+r>>1;
	if(qr<=mid)	return ask(lc[p],l,mid,ql,qr);
	else if(ql>mid)	return ask(rc[p],mid+1,r,ql,qr);
	else return max(ask(lc[p],l,mid,ql,mid),ask(rc[p],mid+1,r,mid+1,qr));
}
signed main(){
	cin>>n>>m;
	for(int i=1,a,b,c,mx;i<=m;i++){
		scanf("%d %d %d",&a,&b,&c);	mx=0;
		mx=ask(rt[a],0,1e5,0,c-1);	res=max(res,mx+1);
		change(rt[b],0,1e5,c,mx+1);
	}
	cout<<res<<endl;
	return 0;
}
发布了416 篇原创文章 · 获赞 228 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43826249/article/details/103827563