USACO 2021 January Contest, Bronze
Problem 1. Uddered but not Herd
一个鲜为人知的事实是,奶牛拥有自己的文字:「牛文」。牛文由 26 个字母 ‘a’ 到 ‘z’ 组成,但是当奶牛说牛文时,可能与我们所熟悉的 ‘abcdefghijklmnopqrstuvwxyz’ 不同,她会按某种特定的顺序排列字母。
为了打发时间,奶牛 Bessie 在反复哼唱牛文字母歌,而 Farmer John 好奇她唱了多少遍。
给定一个小写字母组成的字符串,为 Farmer John 听到 Bessie 唱的字母,计算 Bessie 至少唱了几遍完整的牛文字母歌,使得 Farmer John 能够听到给定的字符串。Farmer John 并不始终注意 Bessie 所唱的内容,所以他可能会漏听 Bessie 唱过的一些字母。给定的字符串仅包含他记得他所听到的字母。
输入格式(从终端/标准输入读入):
输入的第一行包含 26 个小写字母 ‘a’ 到 ‘z’ 的牛文字母表顺序。下一行包含一个小写字母组成的字符串,为 Farmer John 听到 Bessie 唱的字母。字符串的长度不小于 1 1 1 且不大于 1000 1000 1000。
输出格式(输出至终端/标准输出):
输出 Bessie 所唱的完整的牛文字母歌的最小次数。
输入样例:
abcdefghijklmnopqrstuvwxyz
mood
输出样例:
3
在这个样例中,牛文字母表与日常的字母表的排列一致。
Bessie 至少唱了三遍牛文字母歌。有可能 Bessie 只唱了三遍牛文字母歌,而 Farmer John 听到了以下被标记为大写的字母。
abcdefghijklMnOpqrstuvwxyz
abcdefghijklmnOpqrstuvwxyz
abcDefghijklmnopqrstuvwxyz
测试点性质:
- 测试点 2-5 中,牛文字母表与日常的字母表相同。
- 测试点 6-10 没有额外限制。
供题:Nick Wu
分析:
略。
#include<bits/stdc++.h>
using namespace std;
string s,st;
int main(){
freopen("herd.in","r",stdin);
freopen("herd.out","w",stdout);
cin>>s>>st;
int pos=0,ans=1;//当成环查找
for(int i=0;i<st.length();++i){
if(pos==26)//26放在循环开始判断,结尾正好找到26跳出时不需对ans操作
pos=0,++ans;
while(s[pos++]!=st[i])
if(pos==26)
pos=0,++ans;
}cout<<ans<<endl;
fclose(stdin);
fclose(stdout);
return 0;
}
Problem 2. Even More Odd Photos
Farmer John 正再一次尝试给他的 NN 头奶牛拍照( 2 ≤ N ≤ 1000 2≤N≤1000 2≤N≤1000)。
每头奶牛有一个范围在 1 … 100 1…100 1…100 之内的整数的「品种编号」。Farmer John 对他的照片有一个十分古怪的构思:他希望将所有的奶牛分为不相交的若干组(换句话说,将每头奶牛分到恰好一组中)并将这些组排成一行,使得第一组的奶牛的品种编号之和为偶数,第二组的编号之和为奇数,以此类推,奇偶交替。
Farmer John 可以分成的最大组数是多少?
输入格式(从终端/标准输入读入):
输入的第一行包含 NN。下一行包含 NN 个空格分隔的整数,为 NN 头奶牛的品种编号。
输出格式(输出至终端/标准输出):
输出 Farmer John 的照片中的最大组数。可以证明,至少存在一种符合要求的分组方案。
输入样例:
7
1 3 5 7 9 11 13
输出样例:
3
在这个样例中,以下是一种分成最大组数三组的方案。将 1 和 3 分在第一组,5、7 和 9 分在第二组,11 和 13 分在第三组。
输入样例:
7
11 2 17 13 1 15 3
输出样例:
5
在这个样例中,以下是一种分成最大组数五组的方案。将 2 分在第一组,11 分在第二组,13 和 1 分在第三组,15 分在第四组,17 和 3 分在第五组。
供题:Nick Wu
分析:
很显然,这题是个奇偶性判断,计算出奇数偶数的个数 n u m 1 , n u m 2 num1,num2 num1,num2 ,然后:
①偶数先手,则
n
u
m
1
=
=
n
u
m
2
num1==num2
num1==num2 (此时奇数结尾),或者
n
u
m
1
+
1
=
=
n
u
m
2
num1+1==num2
num1+1==num2 (此时偶数结尾)。
②两个奇数可以构成一个偶数,偶数构不成奇数。
则,如果
n
u
m
1
+
1
<
n
u
m
2
num1+1<num2
num1+1<num2 ,则必定有多个偶数挤在一起。
如果
n
u
m
1
>
n
u
m
2
num1>num2
num1>num2 ,则必定有多个两个奇数构成偶数;当两个奇数构成一个偶数时,
n
u
m
1
−
=
2
,
+
+
n
u
m
2
num1-=2,~++num2
num1−=2, ++num2 ,因为最终
n
u
m
2
=
=
n
u
m
1
∣
∣
n
u
m
2
=
=
n
u
m
1
+
1
num2==num1||num2==num1+1
num2==num1∣∣num2==num1+1 ,则讨论
(
n
u
m
1
−
n
u
m
2
)
m
o
d
3
(num1-num2)\mod3
(num1−num2)mod3 的所有可能情况(即完全剩余系)。
如:(定义
d
f
c
=
n
u
m
1
−
n
u
m
2
dfc=num1-num2
dfc=num1−num2 ,所出现的所有 /
符号表示整除)
①
n
u
m
2
=
0
,
n
u
m
1
=
6
num2=0,~num1=6
num2=0, num1=6 ,贪心可得
(
n
u
m
2
=
1
,
n
u
m
1
=
4
)
→
(
n
u
m
2
=
2
,
n
u
m
1
=
2
)
(num2=1,~num1=4)\to(num2=2,~num1=2)
(num2=1, num1=4)→(num2=2, num1=2) ,则
a
n
s
=
2
(
n
u
m
2
+
d
f
c
/
3
)
ans=2(num2+dfc/3)
ans=2(num2+dfc/3) 。
②
n
u
m
2
=
0
,
n
u
m
1
=
7
num2=0,~num1=7
num2=0, num1=7 ,同理可得
(
n
u
m
2
=
1
,
n
u
m
1
=
5
)
→
(
n
u
m
2
=
2
,
n
u
m
1
=
3
)
→
(
n
u
m
2
=
2
,
n
u
m
1
=
1
)
(num2=1,~num1=5)\to(num2=2,~num1=3)\to(num2=2,~num1=1)
(num2=1, num1=5)→(num2=2, num1=3)→(num2=2, num1=1) ,则
a
n
s
=
2
(
n
u
m
2
+
d
f
c
/
3
)
−
1
ans=2(num2+dfc/3)-1
ans=2(num2+dfc/3)−1 。
③
n
u
m
2
=
0
,
n
u
m
1
=
8
num2=0,~num1=8
num2=0, num1=8 ,同理可得
(
n
u
m
2
=
1
,
n
u
m
1
=
6
)
→
(
n
u
m
2
=
2
,
n
u
m
1
=
4
)
→
(
n
u
m
2
=
3
,
n
u
m
1
=
2
)
(num2=1,~num1=6)\to(num2=2,~num1=4)\to(num2=3,~num1=2)
(num2=1, num1=6)→(num2=2, num1=4)→(num2=3, num1=2) ,则
a
n
s
=
2
(
n
u
m
2
+
d
f
c
/
3
)
+
1
ans=2(num2+dfc/3)+1
ans=2(num2+dfc/3)+1 。
则有如下代码:
#include<bits/stdc++.h>
using namespace std;
#define MAXN 1010
int n,oe[2];
int main(){
freopen("group.in","r",stdin);
freopen("group.out","w",stdout);
cin>>n;
int id;
for(int i=1;i<=n;++i){
cin>>id;
++oe[id%2];
}int dfc=oe[1]-oe[0];//difference
if(dfc<0)//偶比奇大
cout<<oe[1]*2+1<<endl;
else if(dfc%3==0)//整除
cout<<(oe[0]+dfc/3)*2<<endl;
else if(dfc%3==1)//余1
cout<<(oe[0]+dfc/3)*2-1<<endl;
else if(dfc%3==2)//余2
cout<<(oe[0]+dfc/3)*2+1<<endl;
fclose(stdin);
fclose(stdout);
return 0;
}
Problem 3. Just Stalling
Farmer John 有 N N N 头奶牛( 1 ≤ N ≤ 20 1≤N≤20 1≤N≤20),高度为 a 1 … a N a_1…a_N a1…aN。他的牛栏有 N N N 个牛棚,高度限制分别为 b 1 … b N b_1…b_N b1…bN(例如,如果 b 5 = 17 b_5=17 b5=17,那么一头高度不超过 17 17 17 的奶牛可以住在牛棚 5 5 5 里)。Farmer John 有多少种不同的方式安排他的奶牛,使得每头奶牛均住在不同的牛棚里,并且使得每个牛棚的高度限制均得到满足?
输入格式(从终端/标准输入读入):
输入的第一行包含 N N N。第二行包含 N N N 个空格分隔的整数 a 1 , a 2 , … , a N a_1,a_2,…,a_N a1,a2,…,aN。第三行包含 NN 个空格分隔的整数 b 1 , b 2 , … , b N b_1,b_2,…,b_N b1,b2,…,bN。所有的高度和高度限制均在范围 [ 1 , 109 ] [1,109] [1,109] 内。
输出格式(输出至终端/标准输出):
输出 Farmer John 可以将每头奶牛安排到不同的牛棚里,使得每个牛棚的高度限制均得到满足的方法数。注意输出的数量可能需要使用 64 位整数型,例如 C++ 中的 long long。
输入样例:
4
1 2 3 4
2 4 3 4
输出样例:
8
在这个例子中,我们不能将第三头奶牛安排到第一个牛棚里,因为 3 = a 3 > b 1 = 2 3=a_3>b_1=2 3=a3>b1=2。类似地,我们不能将第四头奶牛安排到第一或第三个牛棚里。一种符合高度限制的安排方式为将奶牛 1 1 1 安排到牛棚 1 1 1,奶牛 2 2 2 安排到牛棚 2 2 2,奶牛 3 3 3 安排到牛棚 3 3 3,奶牛 4 4 4 安排到牛棚 4 4 4。
测试点性质:
- 测试点 1-5 满足 N ≤ 8 N≤8 N≤8。
- 测试点 6-12 没有额外限制。
供题:Shreyas Thumathy
分析:
状压dp:
如果能想到状压,在纸上模拟一遍就能看出来组合数学。
乘法原理:
计算出每一头奶牛能住进的棚子数量,从个子高的奶牛开始选(因为可选的少),由于个子矮的奶牛一定能住进个子高奶牛能住进的棚子,则在高奶牛选择了一个棚子后,所有矮奶牛的可选棚子数都减少一个,即 a n s = Π i = 1 n ( v h [ i ] − n + i ) ans=\Pi_{i=1}^{n}(vh[i]-n+i) ans=Πi=1n(vh[i]−n+i) ,则有以下两种代码。
O ( n 2 ) O(n^2) O(n2)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int n,a[25],b,vh[25];
ll ans=1;
int main(){
freopen("stalling.in","r",stdin);
freopen("stalling.out","w",stdout);
cin>>n;
for(int i=1;i<=n;++i)
cin>>a[i];
sort(a+1,a+1+n);
for(int i=1;i<=n;++i){
cin>>b;//不需要记录b
for(int j=1;j<=n;++j){
if(a[j]>b)
break;
++vh[j];//每读入一个牛棚高度都对每头奶牛能住进的棚子数量进行操作
}
}for(int i=n;i>=1;--i)
ans*=(vh[i]-n+i);
cout<<ans<<endl;
fclose(stdin);
fclose(stdout);
return 0;
}
O ( n l o g n ) O(nlogn) O(nlogn)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int n,a[25],b[25],vh[25];
ll ans=1;
int main(){
freopen("stalling.in","r",stdin);
freopen("stalling.out","w",stdout);
cin>>n;
for(int i=1;i<=n;++i)
cin>>a[i];
sort(a+1,a+1+n);
for(int i=1;i<=n;++i)
cin>>b[i];
sort(b+1,b+1+n);
int pos=n;
vh[n+1]=0;
for(int i=n;i>=1;--i){
vh[i]=vh[i+1];
for(int j=pos;j>=1;--j){//没必要每次都从头查找
if(b[j]<a[i])
break;
pos=j-1;
++vh[i];
}
}for(int i=n;i>=1;--i)
ans*=(vh[i]-n+i);
cout<<ans<<endl;
fclose(stdin);
fclose(stdout);
return 0;
}