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;
}