您的位置:首页 > 其它

Divide by Zero 2017 and Codeforces Round #399 (Div. 1 + Div. 2, combined)

2017-02-22 20:25 417 查看
这把比赛题目不错,然而打得太挫了。。来写一发题解

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天绝对够了),处理好p取1~1000的答案,再回答。

#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,由组合数学知识,相当于w个小球中间的w−1个位置放i−1个隔板,也就是求一个组合数,此时食物的堆数只能是i−1~i+1,计算方法同酒,然后把它们乘起来。

分子(符合条件的情形数),也是枚举酒的堆数i,因为有高度要求,把酒的数量减去i∗h,再进行与分母一样的运算即可。

#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
;
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  codeforces
相关文章推荐