CF1400:1490E、448B、1462FD、650A、1380B、1451C

1490E. Accidental Victory(二分)

题意:

一共n个人参加比赛,每个人有一个强壮值。
每次随机挑选两人pk,赢的人获得另一人的强壮值。如果强壮值相同,随机赢。
问,最终有哪些人有赢的可能性?

思路:

也就是问,有哪些人必输了。
一个人所得的到的最大强壮值为比其小的所有强壮值之和。

法1:
将所有人从小到大排序。
对于一个位置的前缀和如果不少于下一位置的值,说明当前位置可以胜过下一位置。
如果不能,说明当前位置以及前面所有位置都没有赢的可能。
找出最后一个不会赢的位置。

法2:二分
因为当前位置如果有赢的可能的话,后面的位置一定能赢,所以可以二分第一个能赢的位置。

Code:

const int N = 200010, mod = 1e9+7;
int T, n, m;
PII a[N];

bool check(int mid)
{
    
    
	ll sum=a[mid].first;
	for(int i=1;i<=n;i++)
	{
    
    
		if(i==mid) continue;
		if(a[i].first<=sum) sum+=a[i].first;
		else return 0; 
	}
	return 1;
}

int main(){
    
    
	Ios;
	
	cin>>T;
	while(T--)
	{
    
    
		cin>>n;
		for(int i=1;i<=n;i++){
    
    
			cin>>a[i].first;
			a[i].second=i;
		}
		sort(a+1,a+n+1);
		
		/*法1: 
		ll sum=0,f=0;
		for(int i=1;i<n;i++)
		{
			sum+=a[i].first;
			if(sum<a[i+1].first) f=i;
			
			set<int> st;
			for(int i=f+1;i<=n;i++) st.insert(a[i].second);
			
			cout<<st.size()<<endl;
			for(auto it:st){
				cout<<it<<" ";
			}
			cout<<endl;
		}*/
		
		int l=1,r=n;
		while(l<r)
		{
    
    
			int mid=l+r>>1;
			if(check(mid)) r=mid;
			else l=mid+1;
		}
		
		set<int> st;
		for(int i=l;i<=n;i++) st.insert(a[i].second);
		
		cout<<st.size()<<endl;
		for(auto it:st){
    
    
			cout<<it<<" ";
		}
		cout<<endl;
	}
	
	return 0;
}

448B. Suffix Structures(双指针)

题意:

给定两个字符串a,b,分别判断下列操作是否a能够变为b:
1.只交换两个字符的位置。
2.只删除某些字符。
3.同时使用前面两种操作。

思路:

判断只删除的时候,需要双指针判断b串在a串中,相对顺序不变的出现过。
只交换,判断是否出现次数相同。

Code:


const int N = 200010, mod = 1e9+7;
int T, n, m;
string a,b;

int main(){
    
    
	cin>>a>>b;
	n=a.size(),m=b.size();
	a=" "+a,b=" "+b;
	
	int cnt=0;
	for(int i=1,j=1;i<=m;i++)
	{
    
    
		while(j<n&&a[j]!=b[i]) j++;
		if(a[j]==b[i]) cnt++,j++;
	}
	if(cnt==m&&n!=m){
    
    
		cout<<"automaton";return 0;
	}
	
	for(int i=1;i<=n;i++) mp[a[i]]++;
	
	bool flag=0;
	for(int j=1;j<=m;j++){
    
    
		if(!mp[b[j]]){
    
    
			flag=1;break;
		}
		mp[b[j]]--;
	}
	if(flag){
    
    
		cout<<"need tree";
		return 0;
	}
	
	if(n==m){
    
    
		cout<<"array";
	}
	else cout<<"both";
	 
	return 0;
}

1462D. Add to Neighbour and Remove(思维,枚举答案)

题意:

给定一个长度为 n 的数列,问最少多少次下述操作,各位置元素相等?
选一个位置i,将ai的值加到位置 i-1 或 i+1 上;将位置i删除,后面的元素递补。

思路:

其实,上面的操作其实就是将若干个连续的位置合并为1个位置,变成一个新的数列。
让合并后的所有元素相同。所以我们可以枚举最后所有元素变成的值。
但是整个范围太大了。

但是 1~i 个位置肯定是要合并为1个位置的,所以我们可以枚举第一组合并的位置个数i。
让这组的值作为最后所有元素的值,判断是否能行通。如果能,答案取最小操作数。

Code:

const int N = 200010, mod = 1e9+7;
int T, n, m, a[N];
ll sum;
int ans;

void check(int m)
{
    
    
	sum=0;
	for(int i=1;i<=m;i++) sum+=a[i];
	
	ll t=0;int cnt=m-1;
	for(int i=m+1;i<=n;i++)
	{
    
    
		t+=a[i];cnt++;
		if(sum==t) t=0,cnt--;
		else if(t>sum) return;
	}
	if(t!=0) return;
	ans=min(ans,cnt);
}

int main(){
    
    
	Ios;
	
	cin>>T;
	while(T--)
	{
    
    
		cin>>n;
		for(int i=1;i<=n;i++) cin>>a[i];
		
		ans=1e9;
		for(int len=1;len<=n;len++)
		{
    
    
			check(len);
		}
		cout<<ans<<endl;
	}
	
	return 0;
}

650A. Watchmen(组合)

题意:

给出若干个点,判断有多少对点的两种距离的求算方式所得的结果相同?

思路:

化简等式得,(xi-xj)(yi-yj)=0
所以满足方式的点对,要么x相同,要么y相同,要么都相同。

所以可以求出满足x相同的点对数+y相同的点对数,再减去x和y都相同的点对数

Code:

const int N = 200010, mod = 1e9+7;
int T, n, m, a[N];

int main(){
    
    
	Ios;
	
	cin>>n;
	for(int i=1;i<=n;i++){
    
    
		int p,q;cin>>p>>q;
		x[p]++,y[q]++;
		mp[{
    
    p,q}]++;
	}
	
	ll ans=0;
	for(auto it:x){
    
    
		ll cnt=it.second;
		ans+=cnt*(cnt-1)/2;
	}
	for(auto it:y){
    
    
		ll cnt=it.second;
		ans+=cnt*(cnt-1)/2;
	}
	for(auto it:mp){
    
    
		ll cnt=it.second;
		ans-=cnt*(cnt-1)/2;
	}
	cout<<ans;
	
	return 0;
}

这时候想起来先变形公式了。。


1380B. Universal Solution(思维)

题意:

给定一个字符串a,三种字符:RSP,对应石头、剪刀、布。
可以从一个位置开始循环,输出。
构造一个字符串b,从1开始输出,使得a串分别从n个位置开始循环,通过字符串b顺序输出所得的赢的次数的平均值最大。

思路:

构造字符串b的所有字符为a串中出现最多的字符的敌人。
每次都收割a串中出现次数多的字符的个数。

大胆假设!!

Code:

const int N = 200010, mod = 1e9+7;
int T, n, m;
string a;

int main(){
    
    
	Ios;
	
	cin>>T;
	while(T--)
	{
    
    
		cin>>a;
		int cnt1=0,cnt2=0,cnt3=0;
		for(int i=0;i<a.size();i++)
		{
    
    
			if(a[i]=='R') cnt1++;
			else if(a[i]=='S') cnt2++;
			else cnt3++;
		}
		int maxa=max(cnt1,max(cnt2,cnt3));
		char c;
		if(cnt1==maxa) c='P';
		else if(cnt2==maxa) c='R';
		else c='S';
		
		for(int i=0;i<a.size();i++) cout<<c;
		cout<<endl;
	}
	
	return 0;
}

1451C. String Equality(思维)

题意:

给定长度为n的字符串a,b。给定长度m。通过下面的操作,判断串a能否变换成串b?

  • 交换两个字符的位置。或

  • 选择长度为m的,全部元素都相同的子串,将其全部元素+1。(例’b’变为’c’)

思路:

因为位置能随意变换,所以连续的元素相同的位置不用管。
分别统计出串a、串b中每个元素出现的次数。
遍历串a中每种元素,判断其个数是否大于m:
如果是,就可以将b中的第一个比其大的字符的个数消去m个;
如果不是,就需要b中有一个和该字符相同的字符。如果没有,不合要求。

最后判断是否b中的元素都被消掉了,个数都为0。如果不是,不合要求。

Code:

const int N = 1000010, mod = 1e9+7;
int T, n, m;
char a[N],b[N];
char c[N],d[N];

int main(){
    
    
	Ios;
	
	cin>>T;
	while(T--)
	{
    
    
		mp1.clear();mp2.clear();
		cin>>n>>m;
		cin>>a+1;
		cin>>b+1;
		
		sort(a+1,a+n+1);
		sort(b+1,b+n+1);
		
		for(int i=1;i<=n;i++) mp1[a[i]]++;
		for(int i=1;i<=n;i++) mp2[b[i]]++;
		
		int ans=0;
		for(auto it:mp1)
		{
    
    
			while(it.second>=m)
			{
    
    
				bool flag=0;
				for(int i=it.first-'a';i<26;i++)
				{
    
    
					char c='a'+i;
					if(mp2[c]>=m){
    
    
						mp2[c]-=m;
						flag=1;
						break;
					}
				}
				if(!flag){
    
    
					ans=-1;break;
				}
				it.second-=m;
			}
			if(ans==-1) break;
			if(it.second)
			{
    
    
				if(mp2[it.first]>=it.second) mp2[it.first]-=it.second;
				else{
    
    
					ans=-1;break;
				}
			}
		}
		
		for(auto it:mp2){
    
    
			if(it.second) ans=-1;
		}
		
		if(ans==-1) cout<<"No\n";
		else cout<<"Yes\n";
	}
	
	return 0;
}

Guess you like

Origin blog.csdn.net/Mr_dimple/article/details/121109992