2022/1/1

2022/1/1

[ D. Keep the Average High]( Problem - D - Codeforces (Unofficial mirror site, accelerated for Chinese users) )

思路:

一、将a[i]的每个数-x,那么题目就转换成了,将a[i]分成若干个区间,每个区间内部的小区间之和都大于等于0,(跟求最大字段和有异曲同工之妙。

参考代码:

#include<bits/stdc++.h>
#define ll  long long
#define pii pair<int, int >
#define se second
#define pb push_back
#define pf push_front
#define si size()
#define db double
#define ls (p<<1)
#define rs (p<<1|1)
#define mid (t[p].l+t[p].r)/2
#define fi first
#define se second
using namespace std;
ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
inline void Prin(ll x){if(x < 0){putchar('-');x = -x;}if(x > 9) Prin(x / 10);putchar(x % 10 + '0');}
const int qs=2e5+7;
ll T,n,a[qs];
int main(){
	T=read();
	while(T--){
		n=read();
		for(int i=1;i<=n;++i) a[i]=read();
		ll x; x=read();
		ll ans=0,y=1e9;
		for(int i=1;i<=n;++i){
			a[i]-=x;
			int flag=0;
			if(y+a[i]<0){
				ans++; flag=1;
			}
			y=min(a[i],y+a[i]);
			if(flag){
				y=1e9;
			}
		}
		cout<<n-ans<<"\n";
	}
	return 0;
}

二、dp

\(f[i][j]\)表示第i个数往前连续选j个数的区间长度

观察样例会发现,只有区间长度为0,1,2的情况为特殊情况,长度>=3的为一种情况

参考代码

#include<bits/stdc++.h>
#define ll  long long
#define pii pair<int, int >
#define se second
#define pb push_back
#define pf push_front
#define si size()
#define db double
#define ls (p<<1)
#define rs (p<<1|1)
#define mid (t[p].l+t[p].r)/2
#define fi first
#define se second
using namespace std;
ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
inline void Prin(ll x){if(x < 0){putchar('-');x = -x;}if(x > 9) Prin(x / 10);putchar(x % 10 + '0');}

const int qs=2e5+7;
ll T,n,a[qs];
ll f[qs][4];
int main(){
	T=read();

	while(T--){
		n=read();
		for(int i=1;i<=n;++i) {
			a[i]=read();
			f[i][0]=f[i][1]=f[i][2]=f[i][3]=0;
		}
		ll x; x=read();
		ll ans=0;
		for(int i=1;i<=n;++i){
			f[i][0]=max(max(f[i-1][0],f[i-1][1]),max(f[i-1][2],f[i-1][3]));
			f[i][1]=f[i-1][0]+1;
			if(i>1&&a[i]+a[i-1]>=2*x){
				f[i][2]=f[i-1][1]+1;
				if(i>2&&a[i]+a[i-1]+a[i-2]>=3*x&&a[i-1]+a[i-2]>=2*x){
					f[i][3]=max(f[i-1][2]+1,f[i-1][3]+1);
				}
			}
		}
		cout<<max(max(f[n][0],f[n][1]),max(f[n][2],f[n][3]))<<"\n";
		
	}
	
	return 0;
}

[E. Lexicographically Small Enough]( Problem - E - Codeforces (Unofficial mirror site, accelerated for Chinese users) )

思路

首先把26个字母分类统计,考虑交换字母时,分两种情况,设当前字母是x:

  1. 找比x小的字母。枚举<=x的字母,找到一个下标最小且没被使用过的,直接前缀和记录答案。
  2. 等于x。在保存x的队列中取出队头,设当前下标为i,队头下标为j,那么总次数需要加上 j-1 的前缀和(即前j-1个没有被使用过的),再将j下标的值-1(标记为用过),并抛出队列

参考代码

#include<bits/stdc++.h>
#define ll  long long
#define pii pair<char, int >
#define se second
#define pb push_back
#define pf push_front
#define si size()
#define db double
#define ls (p<<1)
#define rs (p<<1|1)
#define mid (t[p].l+t[p].r)/2
#define fi first
#define se second
using namespace std;
ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
inline void Prin(ll x){if(x < 0){putchar('-');x = -x;}if(x > 9) Prin(x / 10);putchar(x % 10 + '0');}

const int qs=2e5+7;

int T,n;
string a,b;
queue<int> q[500]; 
int val[qs];

int lb(int x){
	return (x&(-x));
}

void add(int x,int k){
	for(;x<=n;x+=lb(x)) val[x]+=k;
}
ll ask(ll x){
	ll ret=0;
	for(;x>0;x-=lb(x)) ret+=val[x];
	return ret;
}
int main(){
	T=read();

	while(T--){
		n=read();	
		cin>>a; a=" "+a;
		cin>>b; b=" "+b;
		for(int i='a';i<='z';++i) {
			while(q[i].si) q[i].pop();
		}
		for(int i=1;i<=n;++i) val[i]=0;
		for(int i=1;i<=n;++i){
			q[a[i]].push(i); 
			add(i,1);
		}
		ll ans=1e12,sum=0;
		for(int i=1;i<=n;++i){
			for(int j='a';j<b[i];++j){
				if(q[j].si){
					ll p=ask(q[j].front()-1);
					ans=min(ans,sum+p);
				}
			}
			if(!q[b[i]].si) break;
			ll p=ask(q[b[i]].front()-1);
			sum+=(p);
			add(q[b[i]].front(),-1);
			q[b[i]].pop();
		}
		if(ans==1e12) ans=-1;
		cout<<ans<<"\n";
	}
	
	return 0;
}

[ C. Set or Decrease]( Problem - C - Codeforces (Unofficial mirror site, accelerated for Chinese users) )

思路

二分答案。

先排个序,接着二分次数,枚举变数组后面几个,其他次数全给a[1]。

参考代码

#include<bits/stdc++.h>
#define ll  long long
#define pii pair<char, int >
#define se second
#define pb push_back
#define pf push_front
#define si size()
#define db double
#define ls (p<<1)
#define rs (p<<1|1)

#define fi first
#define se second
using namespace std;
ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
inline void Prin(ll x){if(x < 0){putchar('-');x = -x;}if(x > 9) Prin(x / 10);putchar(x % 10 + '0');}

const int qs=2e5+7;

ll T,n,k,a[qs],sum;

int ck(ll x){
	ll all=sum;
	
	if(all-x<=k) return 1;
	all-=a[1];
	ll f=a[1];
	for(int i=n;i>=2&&x>=(n-i+1);--i){
		all-=a[i];
		ll fp=all+(f-(x-(n-i+1)))*(n-i+2);
		if(fp<=k) return 1;
	}
	return 0;
}

int main(){
	T=read();

	while(T--){
		n=read(),k=read();	
		sum=0;
		for(int i=1;i<=n;++i) a[i]=read(),sum+=a[i];
		sort(a+1,a+1+n);
		int l=0,r=1e12,ans;
		while(l<=r){
			int md=(l+r)/2;
			if(ck(md)) r=md-1,ans=md;
			else l=md+1;
		}
		cout<<ans<<"\n";
	}
	
	return 0;
}


posted @ 2022-01-01 22:58  Suki_Sugar  阅读(249)  评论(0编辑  收藏  举报
Live2D