Yandex.Algorithm Online Round 3 Sunday, June 15, 2014





Problem A. Distance 求树中距离恰好为2的结点对的个数


#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int edge[100007];

int main(){
    int t;
    while(scanf("%d",&t)!=EOF){
        for(int i = 1;i <= t; i++)
            edge[i] = 0;
        int u,v;
        for(int i =1 ;i < t; i++){
            scanf("%d%d",&v,&u);
            edge[u]++;
            edge[v]++;
        }
        long long ans = 0;
        for(int i = 1;i <= t; i++){
            ans += (1ll*edge[i]*edge[i]-edge[i])/2;
        }
        cout<<ans<<endl;
    }
    return 0;
}


Problem B. Science

求长度为n只有01的字符串,包含01{k}0子串个数的期望 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

struct Node{
    double max[107][107];
};
int k;
Node operator *(Node a,Node b){
    Node c;
    memset(c.max,0,sizeof(c.max));
    for(int i = 0;i <= k + 2; i++){
        for(int j = 0;j <= k+2; j++){
            for(int l = 0;l <= k+2; l++){
                c.max[i][j] += a.max[i][l]*b.max[l][j];
            }
        }
    }
    return c;
}
Node x,y,z;
int main(){
    long long n;
    while(cin>>n>>k){
        memset(x.max,0,sizeof(x.max));
        for(int i = 0;i <= k+2 ;i++)
            x.max[i][i] = 1.0;
        memset(y.max,0,sizeof(y.max));
        for(int i = 0;i <= k; i++)
            y.max[0][i] = 0.5;
        for(int i = 1;i <= k+1; i++)
            y.max[i][i-1] = 0.5;
        y.max[0][k+1] = 0.5;
        y.max[k+1][k+1] = 0.5;
        y.max[k+2][k] = 0.5;
        y.max[k+2][k+2] = 1.0;
        n--;
        while(n){
            if(n&1) x = x*y;
            y = y * y;
            n /= 2;
        }
        double ans = x.max[k+2][0]*0.5 + x.max[k+2][k+1]*0.5;
        printf("%0.16f\n",ans);
    }
    return 0;
}














Problem C. Intervals

求有几个区间,在这个区间中存在两个数,差值为d

#include<iostream>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
#include<cstdio>
#define ll long long
using namespace std;
map<ll,int> haha;
int main(){
    int n,d;
    while(scanf("%d%d",&n,&d)!=EOF){
        haha.clear();
        int be = 0;
        haha[0] = 0;
        ll sum = 0,u;
        ll ans = 0;
        for(int i = 1;i <= n; i++){
            scanf("%I64d",&u);
            if(haha.find(u-d)!= haha.end())
                be = max(be,haha[u-d]);
            if(haha.find(u+d) != haha.end())
                be = max(be,haha[u+d]);
            ans += be;
            haha[u] = i;
        }
        cout<<ans<<endl;
    }
    return 0;
}


F. Weird Game

对于长度为N的一维格子,每次可以从中选出恰好长度为L,且不包含被染色位置的格子。

如果找不到可以染色的区间了。算输。

sg函数 对于可以选择长度为L进行染色,算出 格子长度为1-7000的sg函数。

由于对于一个N,要枚举分出的两个线段长度,需要N的转移,所以是N*N的复杂度,会超时。

打表找规律,发现大于8的L的必败态有固定的增长速度。于是,打表。

小于8的就直接sg函数做了就行。


#include<cstdio>
#include<cstring>
#include<algorithm>
#include<bitset>
#include<iostream>
#include<set>
using namespace std;

int check[7000];
int sg[7000];
set<int> haha[70001];

int change[14][2]={
2,0,
2,0,
4,-2,
4,-2,
4,0,
4,-2,
8,-2,
4,-2,
8,0,
8,-2,
16,-6,
4,0
};

int main(){
    int cnt = 1;
    for(int i = 2;i <= 7;i++){
        memset(sg,0,sizeof(sg));
        for(int j = i; j <= 7000; j++){
            int u = j - i;
            for(int k = 0;k + k <= u; k++){
                check[sg[k]^sg[u-k]] = cnt;
            }
            for(int k = 0;;k++){
                if(check[k] != cnt){
                    sg[j] = k;
                    break;
                }
            }
            cnt++;
        }
        int f = 0;
        for(int j = i;j <= 7000; j++){
           if(sg[j] == 0){
               haha[i].insert(j);
           }
        }
    }

    for(int i = 8; i<=7000;i++){
        int j = i -1;
        for(int l = 0;l < 12; l++){
            j = j + change[l][0]*i+change[l][1];
            if(j > 7000) break;
            haha[i].insert(j);
        }
    }


    int n;
    while(scanf("%d",&n)!=EOF){
        if(n % 2 == 0) printf("S");
        else printf("F");
        for(int i = 2;i <= n; i++){
            if(haha[i].find(n) != haha[i].end()) printf("S");
            else printf("F");
        }
        printf("\n");
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GDRetop

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值