USACO测试赛2

本文详细分析了USACO测试赛2的三个问题:奶牛唱歌、照片分组和牛舍安排。在奶牛唱歌中,需要判断字母顺序决定重唱次数;照片分组通过分类讨论解决;牛舍安排运用组合数学优化解决方案。同时,文章还介绍了如何使用状态压缩动态规划来解决相关问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

USACO测试赛2

1.奶牛唱歌

在这里插入图片描述
在这里插入图片描述
将每个字母在奶牛字母表中的顺序打出来,遍历时如果第i个字符在第i-1个字符前面的话,就要再唱一遍,否则不需要。

#include <bits/stdc++.h>
using namespace std;

string s,st;
map<char,int> vh;
int ans=1;

int main(){
	freopen("herd.in","r",stdin);
	freopen("herd.out","w",stdout);
	cin >> s >> st;
	int len=s.size(),l=st.size();
	for(int i=0;i<len;++i)
		vh[s[i]]=i;
	for(int i=1;i<l;++i){
		if(vh[st[i]]<=vh[st[i-1]])
		  ans++;
	}
	cout << ans << endl;
	fclose(stdin);
	fclose(stdout); 
	return 0;
}

2.照片分组

在这里插入图片描述
在这里插入图片描述

分类讨论

我们先讨论两种简单的情况:
1.当偶数的个数等于奇数的个数时,那么结果一定是偶数的个数+奇数的个数,因为直接一个偶配一个奇就可以了。
2.当偶数的个数大于奇数的情况时,前面可以做到一个偶配一个奇,而后面多出来的部分则必须全部相加,合成一个偶数才可以,结果就是偶数的个数*2+1。

然后讨论一种比较复杂的情况:
当奇数的个数大于偶数的个数时,前面的部分同样可以直接配对,而后面的部分就需要三个分成一队,先两个奇数合成一个偶数,再用一个奇数,然后反复即可。如果多出来的部分%3余1的话,就无法正好分配,这时用一个奇数和一个偶数合成一个奇数,就可以避开这个问题。
那么最后的结果除去前面的正好分配,剩下的部分如果是3的倍数的话,乘2即可,否则要再加上一个1.

#include <bits/stdc++.h>
using namespace std;

int n,a[1010];
vector<int> odd;
vector<int> even;//可以不用存,维护个数就行了

int main(){
	freopen("group.in","r",stdin);
	freopen("group.out","w",stdout);
	cin >> n;
	for(int i=1;i<=n;++i)
	   cin >> a[i];
	for(int i=1;i<=n;++i){
		if(a[i]%2==1)
		  odd.push_back(a[i]);
		else
		  even.push_back(a[i]);
	}
	int ans=0;
	if(odd.size()>even.size()){
		if(even.size()==0){
			odd.pop_back();
			odd.pop_back();
			even.push_back(2);
		}
		if((odd.size()-even.size())%3==1)
			even.pop_back();
		ans+=2*even.size();
		if((odd.size()-even.size())%3==2)
			ans+=(odd.size()-even.size())/3*2+1;
		if((odd.size()-even.size())%3==0)
		    ans+=(odd.size()-even.size())/3*2;
	}
	if(odd.size()==even.size())
		ans+=odd.size()*2;
	if(odd.size()<even.size())
		ans+=odd.size()*2+1;
	cout << ans << endl;
	fclose(stdin);
	fclose(stdout);
	return 0;
}

3.牛舍安排

在这里插入图片描述
在这里插入图片描述

组合数学

首先算出每一头奶牛可以放的位置有多少,如样例:
第一头奶牛可以放4个位置,
第二头奶牛可以放4个位置,
第三头奶牛可以放3个位置,
第四头奶牛可以放2个位置。
那么第一个位置就可以放两头奶牛(1,2),ans乘2,第二个位置就可以放三头奶牛(1,2,3),但因为第一个位置放了一头,ans只能乘2,第三个位置可以放4头牛,但因为已经放了2头,所以ans只能乘2,最后一个位置能放4头牛,但已经放了3头牛,ans只能乘1.
这样做即可。

#include <bits/stdc++.h>
using namespace std;
#define ll long long

int n,a[25],b[25];
ll id[25],vh[25];

int main(){
	freopen("stalling.in","r",stdin);
	freopen("stalling.out","w",stdout);
	cin >> n;
	for(int i=1;i<=n;++i)
	   cin >> a[i];
	for(int i=1;i<=n;++i)
	   cin >> b[i];
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)
			if(b[j]>=a[i])
			  id[i]++;
	ll ans=1,op=0;
	for(int i=1;i<=n;++i)
		vh[id[i]]++;
	for(int i=n;i>=1;--i){
		vh[i]+=op;
		op=vh[i];
	}
	for(int i=n;i>=1;--i){
		if(vh[i]!=0)
			ans*=(vh[i]-(n-i));
	}
	cout << ans << endl;
	fclose(stdin);
	fclose(stdout);
	return 0;
}

状压dp

用一串二进制数s来表示牛棚的状态,考虑第k头牛,枚举所有位置,如果可以放,则mv+=f(s),s要更新一下,最后加上记忆化也能AC。

#include <bits/stdc++.h>
using namespace std;
#define ll long long

int n,a[25],b[25];
ll dp[2097300];
bitset<25> s;

ll f(bitset<25> s){
	int k=s.count()+1;
	if(dp[s.to_ulong()]!=-1)
	  return dp[s.to_ulong()];
	if(s.count()==n-1){
		int op=0;
		for(int i=1;i<=n;++i){
			if(s[i]==0){
				op=i;
				break;
	    	}
		}
		if(a[k]<=b[op])	  
		  return dp[s.to_ulong()]=1;
		else
		  return dp[s.to_ulong()]=0;
	}
	ll mv=0;
	for(int i=1;i<=n;++i){
		if(s[i]==0 && a[k]<=b[i]){
			s.flip(i);
			mv+=f(s);
			s.flip(i);
		}
	}
	return dp[s.to_ulong()]=mv;
}

int main(){
	freopen("stalling.in","r",stdin);
	freopen("stalling.out","w",stdout);
	memset(dp,-1,sizeof(dp));
	cin >> n;
	for(int i=1;i<=n;++i)
	   cin >> a[i];
	for(int i=1;i<=n;++i)
	   cin >> b[i];
	cout << f(s) << endl;
	fclose(stdin);
	fclose(stdout);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值