这把比赛题目不错,然而打得太挫了。。来写一发题解
C. Jon Snow and his Favourite Number
基本上是暴力模拟,不过排序和异或要写 O(1000) 的。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010;
int n,k,x;
int cnt[1024][2];
int main(){
cin>>n>>k>>x;
for(int i=0;i<n;i++){
int num;
scanf("%d",&num);
cnt[num][0]++;
}
int cur = 0;
int pre = 1;
while(k--){
swap(cur,pre);
//sort
for(int i=0;i<1024;i++){
cnt[i][cur] = 0;
}
int p = 0;
for(int i=0;i<1024;i++){
cnt[i][cur] += cnt[i][pre]>>1;
cnt[i^x][cur] += cnt[i][pre]>>1;
if((cnt[i][pre])&1){
if(p&1){
cnt[i][cur]++;
}else{
cnt[i^x][cur]++;
}
}
p+=cnt[i][pre];
}
}
for(int i=1023;;i--){
if(cnt[i][cur]){
cout<<i<<" ";
break;
}
}
for(int i=0;;i++){
if(cnt[i][cur]){
cout<<i<<endl;
break;
}
}
return 0;
}
D. Jon and Orbs
考虑到每个orb是等价的,状态用当前已有多少个orb来表示。递推计算出来每天有1~
k
个orb的概率(题目要求的最大概率是1/2,递推到第100000天绝对够了),处理好
#include <bits/stdc++.h>
using namespace std;
double p_count[1010];
int ans[1010];
int main(){
int k,q;
cin>>k>>q;
int p = 1;
double target;
for(int i=0;i<=k;i++){
p_count[i] = 0;
}
p_count[0] = 1.0;
for(int day = 1;p<=1000;day++){
target = (p+0.0)/2000;
for(int i=k;i>0;i--){
double tmp = p_count[i-1] * ((k-i+1.0)/k);
p_count[i] += tmp;
p_count[i-1] -= tmp;
}
while(p_count[k] >= target){
ans[p] = day;
p++;
target = (p+0.0)/2000;
if(p>1000)break;
}
}
while(q--){
cin>>p;
cout<<ans[p]<<endl;
}
return 0;
}
E. Game of Stones
很有意思的一个题。解题的关键是注意到一堆数量为1的石子和一堆数量为2的石子是等效的。因为这两种堆都只能够被拿一次。仔细分析我们会发现,石子的数量在1以上,相当于传统nim的1,石子的数量在1+2=3以上,相当于传统nim的2,石子的数量在1+2+3=6以上,相当于传统nim的3…把每堆数量转化一下,就是变成一个传统的nim博弈问题了。另外每堆上限仅60,据说可以搜索。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int cnt[66];
int a[66];
int main(){
int n;
cin>>n;
for(int i=0;i<n;i++){
int num;
scanf("%d",&num);
cnt[num]++;
}
for(int i=1;i<=60;i++){
a[i] = a[i-1] + i;
}
vector<int> p;
for(int i=1;i<=60;i++){
cnt[i] %= 2;
}
for(int i=1;i<=60;i++){
if(cnt[i]){
for(int j=1;j<=60;j++){
if(a[j]>i){
cnt[j-1]++;
cnt[i]--;
break;
}
}
}
}
int sum = 0;
for(int i=1;i<=60;i++){
while(cnt[i]--){
sum ^= i;
}
}
if(sum){
puts("NO");
}else{
puts("YES");
}
return 0;
}
F. Barrels and boxes
组合数学问题。先说分母(总数),枚举酒的堆数
i
,由组合数学知识,相当于
分子(符合条件的情形数),也是枚举酒的堆数
i
,因为有高度要求,把酒的数量减去
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod = 1e9 + 7;
ll fac[100010];
//扩展欧几里德
void ExEuclid(ll a,ll b,ll &x,ll &y,ll &q){
if(b==0){
x=1;y=0;q=a;
return;
}
ExEuclid(b,a%b,y,x,q);
y-=x*(a/b);
}
//逆元
ll inv(ll num){
ll x,y,q;
ExEuclid(num,mod,x,y,q);
if(q==1)return (x+mod)%mod;
}
ll C(int n,int k){
if(n<0 || k<0)return 0;
if(n<k)return 0;
ll res = fac[n];
res *= inv(fac[k]);
res %= mod;
res *= inv(fac[n-k]);
res %= mod;
return res;
}
ll solve(int f,int w,int mn,int mx){
if(w == 0 || f == 0)return 1;
ll res = 0;
// w -> i
for(int i=mn;i<=mx;i++){
ll t = C(w-1,i-1);
if(i>1){
res += t * C(f-1,i-2);
}
res += t * C(f-1,i-1) * 2;
res += t * C(f-1,i);
res %= mod;
}
res %= mod;
return res;
}
int main(){
fac[0] = 1;
for(int i=1;i<=100000;i++){
fac[i] = fac[i-1] * i;
fac[i] %= mod;
}
int f,w,h;
cin>>f>>w>>h;
//p/q
ll p = 0;
ll q = 0;
if( h == 0){
p = solve(f,w,1,w);
q = solve(f,w,1,w);
}else{
q = solve(f,w,1,w);
for(int i=1;;i++){
int ww = w - i*h;
if(ww<i)break;
p += solve(f,ww,i,i);
}
p %= mod;
if(w == 0){
p = 1;
q = 1;
}
}
ll ans = p * inv(q);
ans %= mod;
cout<<ans<<endl;
return 0;
}