Educational Codeforces Round 96 (Rated for Div. 2) A-E

 (353)xxx5187 +00:05+00:10+100:28+00:53+01:21

 

A:

倒着枚举就行,复杂度是够的,不要纯On^2就行。。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define re register
#define ls (o<<1)
#define rs (o<<1|1)
//#define m (l+r)/2
#define pb push_back
typedef pair<int,int> pii;
const double PI= acos(-1.0);
const int M = 1e5+7;
/*
int head[M],cnt=1;
void init(int n){cnt=1;for(int i=0;i<=n;i++)head[i]=0;}
struct EDGE{int to,nxt,w;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}
*/
int a[M];
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
  	int t;
  	cin>>t;
  	while(t--){
  		int n;
		cin>>n;
		bool f=false;
		int a=-1,b,c;
  		for(int i=0;i*7<=n;i++){
  			int tp=n-i*7;
  			if(f)break;
  			for(int j=0;j*5<=tp;j++){
  				int tp2=tp-=j*5;
  				if(tp2%3==0){
  					f=true;
  					a=i,b=j,c=tp2/3;
  					break;
				}
			}
		  }
		if(a==-1)cout<<-1<<endl;
		else cout<<c<<" "<<b<<" "<<a<<endl;
	}
  	
	return 0;
}

B:

显然一次倒水后,最小值就变成了0,每次只需要倒次大的给最大的即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define re register
#define ls (o<<1)
#define rs (o<<1|1)
//#define m (l+r)/2
#define pb push_back
typedef pair<int,int> pii;
const double PI= acos(-1.0);
const int M = 2e5+7;
/*
int head[M],cnt=1;
void init(int n){cnt=1;for(int i=0;i<=n;i++)head[i]=0;}
struct EDGE{int to,nxt,w;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}
*/
int a[M];
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
  	int t;
  	cin>>t;
  	while(t--){
  		int n,k;
  		cin>>n>>k;
  		for(int i=1;i<=n;i++)cin>>a[i];
  		ll ans=0;
  		sort(a+1,a+1+n);
  		if(k==0){
  			cout<<a[n]-a[1]<<endl;
  			continue;
		}
		ans=a[n];
  		for(int i=n-1;i>=n-k;i--){
  			ans+=a[i];
		}
		cout<<ans<<endl;
	}
	return 0;
}

C:

每次选择最右边两个数,最终得到的数一定是2,而结果不可能小于2,因为1与另一个不为1的数消去最小是2.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define re register
#define ls (o<<1)
#define rs (o<<1|1)
//#define m (l+r)/2
#define pb push_back
typedef pair<int,int> pii;
const double PI= acos(-1.0);
const int M = 1e5+7;
/*
int head[M],cnt=1;
void init(int n){cnt=1;for(int i=0;i<=n;i++)head[i]=0;}
struct EDGE{int to,nxt,w;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}
*/

int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
  	int t;
  	cin>>t;
  	while(t--){
  		int n;
  		cin>>n;
  		ll sm=0;
  		sm=(1+n)*n/2;
  		cout<<2<<endl;
  		cout<<n-1<<" "<<n<<"\n";
  		for(int i=n-2;i>=1;i--)
  		cout<<i<<" "<<i+2<<"\n";
  		
	}
	return 0;
}

D:

一个比较显然的贪心:

先把01串分段,连续相同的为一段。

从左往右处理每段,每次操作一肯定是先消去最前面且段长不为1的段,然后2操作把最前面的段消去。这样能保证2操作能做更多次,即结果最大!

然后找数组最左边不为1的数,并使它减一,用线段树即可处理。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define re register
#define ls (o<<1)
#define rs (o<<1|1)
#define m (l+r)/2
#define pb push_back
typedef pair<int,int> pii;
const double PI= acos(-1.0);
const int M = 2e5+7;
/*
int head[M],cnt=1;
void init(int n){cnt=1;for(int i=0;i<=n;i++)head[i]=0;}
struct EDGE{int to,nxt,w;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}
*/
char s[M];
int p[M],sz=0;
int tr[M<<2];
void bd(int o,int l,int r){
	tr[o]=0;
	if(l==r){
		return ;
	}
	bd(ls,l,m);
	bd(rs,m+1,r);
}
void up(int o,int l,int r,int x,int d){
	if(l==r){
		tr[o]+=d;
		return ;
	}
	if(x<=m)up(ls,l,m,x,d);
	else up(rs,m+1,r,x,d);
	tr[o]=tr[ls]+tr[rs];
}
int qu(int o,int l,int r,int x,int y){//区间最左边不为1的数的位置 
	
	if(l==r)return l;
	if(x<=m){
		if(tr[ls]>m-l+1)return qu(ls,l,m,x,y);
	}
	if(y>m){
		if(tr[rs]>r-m)return qu(rs,m+1,r,x,y);
	}
	return -1;
}
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
  	int t;
  	cin>>t;
  	while(t--){
  		int n;
  		cin>>n;
  		cin>>(s+1);
  		int nm=0;sz=0;
  		
  		for(int i=1;i<=n;i++){
  			nm++;
			if(s[i]!=s[i+1]){
				p[++sz]=nm;
				nm=0;
			}
		}bd(1,1,sz);
		for(int i=1;i<=sz;i++)up(1,1,sz,i,p[i]);
		//cout<<i<<" - "<<p[i]<<endl;;
		int ans=0;
		for(int i=1;i<=sz;i++){
			int id=qu(1,1,sz,i,sz);
			ans++;
			if(id<i||p[id]==1){
				
				if(i+1<=sz)up(1,1,sz,i+1,-p[i+1]+1);
				i++;
			}
			else{
				up(1,1,sz,id,-1);
				p[id]--;
			}
			up(1,1,sz,i,-p[i]+1);//用过的都赋值为1 
		}
		cout<<ans<<endl;
	}
	return 0;
}

E:

把一个串通过移动相邻串移动成其反转串。

看到相邻串移动就能先到逆序对。

显然对于一个串a。

移动到串b,一定是从左往右第i个'a',相对齐,然后跑个逆序对即可。

例如:

abac 

caba

1234

4123 (反转串第一个字符'c' 在原串4位置上,第二个字符'a',是第一个'a',在原串1位置上,后面类似。。)

求4123逆序对个数即可。。

仔细想一下这里为什么成立,其实对逆序对足够熟练,这题就很裸了。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define re register
#define ls (o<<1)
#define rs (o<<1|1)
//#define m (l+r)/2
#define pb push_back
typedef pair<int,int> pii;
const double PI= acos(-1.0);
const int M = 4e5+7;
/*
int head[M],cnt=1;
void init(int n){cnt=1;for(int i=0;i<=n;i++)head[i]=0;}
struct EDGE{int to,nxt,w;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}
*/
int c[M];
int n;
void add(int x,int d){
	while(x<=n){
		c[x]+=d;
		x+=x&(-x);
	}
}
ll qu(int x){
	ll ans=0;
	while(x){
		ans+=c[x];
		x-=x&(-x);
	}
	return ans;
}
char s[M],p[M];

int nm[M],g[55];
vector<int> v[55];
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
  	cin>>n>>(s+1);
  	for(int i=1;i<=n;i++){
  		p[i]=s[n-i+1];
	}
	for(int i=1;i<=n;i++){
		v[p[i]-'a'+1].pb(i);
	}
	for(int i=1;i<=n;i++){
		int ch=s[i]-'a'+1;
		nm[i]=v[ch][g[ch]];
		++g[ch];
	}
//	cout<<"oko "<<endl;
	ll ans=0;
	for(int i=1;i<=n;i++){
	//	cout<<i<<" "<<t[i]<<endl;
		add(nm[i],1);
		ans+=qu(n);
		ans-=qu(nm[i]);
	//	cout<<qu(n)
	}
	cout<<ans<<endl;
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值