组队赛2 - 2014.7.20 - 2013长春现场赛

B - Golden Radio Base

problem

给你一个数[1, 1e9],写出他的φ 进制。其中φ = (1+√5)/2  。

think

1<φ<2所以答案只包括0和1和小数点。在题目中给了两个重要信息。写成φ进制表示就是:

1)11 = 100

2)200 = 1001 (同理 2 = 10.01

于是就可以这样加下去了。可是1e9太大了,于是使用快速幂的思想。

code

int str[400];
int tmp[400];
int n;
void out() {
        int st, ed;
        for (int i = 0; i < 400; i++) if (str[i]) {
            st = i;
            break;
        }
        for (int i = 399; i >= 0; i--) if (str[i]) {
            ed = i;
            break;
        }
        for (int i = st; i <= 200; i++) printf("%d", str[i]);
        if (ed > 200) {
            printf(".");
            for (int i = 201; i <= ed; i++) printf("%d", str[i]);
        }
        puts("");
}
void gao(int str[], int tmp[]) {
    for (int i = 0; i < 400; i++) str[i] += tmp[i];
    int k = 0;
    while(k < 400) {
        if (str[k] >= 2) {
            str[k - 1] += 1; str[k] -= 2; str[k + 2] += 1;
            k--;
        }
        else if (k > 0 && str[k] == 1 && str[k - 1] == 1) {
            str[k] = 0; str[k - 1] = 0; str[k - 2] += 1;
            k -= 2;
        }
        else k++;
    }
}
void fi_pow(int k) {
    memset(tmp, 0, sizeof(tmp)); memset(str, 0, sizeof(str));
    tmp[200] = 1;
    while(k) {
        if (k & 1) gao(str, tmp);
        gao(tmp, tmp);
        k >>= 1;
    }
}
int main () {
    while(~scanf("%d", &n)) {
        if (n == 1) {
            puts("1");
            continue;
        }
        fi_pow(n);
        out();
    }
    return 0;
}

直接模拟

由于 2 = 10.01

所以 x = (x/2)(x%2).0(x/2)

500+ms, 上一个方法700+ms

code

int main () {
    int n;
    while(~scanf("%d", &n)) {
        if (n == 1) {
            puts("1");
            continue;
        }
        memset(str, 0, sizeof(str));
        str[200] = n;
        bool flag = true;
        while(flag){
            flag = 0;
            for(int i = 390; i > 0; --i){
                if(str[i] >= 2){
                    str[i-1] += str[i] / 2;
                    str[i+2] += str[i] / 2;
                    str[i] %= 2;
                    flag = 1;
                    //out();
                }
            }
            for(int i = 390; i > 0; --i){
                if(i > 0 && str[i] && str[i-1]){
                    int tmp = min(str[i], str[i-1]);
                    str[i] -= tmp;
                    str[i-1] -= tmp;
                    str[i-2] += tmp;
                    flag = 1;
                }
            }
        }
        out();
    }
    return 0;
}


C - Little Tiger vs. Deep Monkey

problem

给出n个比赛。输得0分。赢得ai分。问要的至少多少分才有p的概率比另一个人多。

think

1)算出每种得分的概率。最多40*1000种得分。

2)其地推公式是:

   p[i][j] += p[i-1][j] / 2; //表示输了,没得分,
   p[i][j+score] += p[i-1][j] / 2;  //表示赢了,得score分。

   两种情况各占一半,所以都是p[i-1][j] / 2。

3)这样精度会爆。由于只有除以2,最多n次除以2,所以把1映射成(1<<n),这样用long long就可以了。

code

LL p[44][44000];

int main()
{
    int T, n, sc;
    double P;
    scanf("%d", &T);
    while(T--){
        scanf("%d%lf", &n, &P);
        P *= (1LL<<n);
        memset(p, 0, sizeof(p));
        p[0][0] = (1LL<<n);
        int tmp = 0;
        for(int i = 1; i <= n; ++i){
            scanf("%d", &sc);
            for(int j = 0; j <= tmp; ++j){
                LL ttt = p[i-1][j] / 2LL;
                p[i][j] += ttt;
                p[i][j+sc] += ttt;
            }
            tmp += sc;
        }
        LL tt = 0;
        int ans = 0;
        for(int j = 0; tt < P; ++j){
            tt += p[n][j];
            ans = j;
        }
        printf("%d\n", ans);
    }
    return 0;
}


I - String

problem

在一个串str种,有多少子串满足这样的条件。长度为M*L,分为M节每节是挨着的L长度。每一节不完全相同。

think

哈希。

字符串的哈希为:a[i] = a[i+1] * seek + str[i] - 'a' + 1;

那么j到j+len之间的字符串的哈希值是:a[j] - a[j+L]*base[L];

然后用map。

code

const int MAXN = 111111;
const ULL seek = 31;

char str[MAXN];
int num[MAXN];
ULL a[MAXN];
ULL b[MAXN];
ULL base[MAXN];
map<ULL , int> mp;

int main(){
    int M, L, N;
    base[0] = 1;
    for(int i = 1; i < MAXN; ++i) base[i] = base[i-1]*seek;
    while(scanf("%d%d%s", &M, &L, str) != EOF){
        N = strlen(str);
        a[N] = 0;
        for(int i = N - 1; i >= 0; --i) a[i] = a[i+1] * seek + str[i] - 'a' + 1;
        int ans = 0;
        for(int i = 0; i < L && i + M*L <= N; ++i){
            mp.clear();
            for(int j = i; j < i + M*L; j += L){
                ULL tmp = a[j] - a[j+L]*base[L];
                ++mp[tmp];
            }
            if(mp.size() == M) ++ans;

            for(int j = i + M*L; j + L <= N; j += L){
                ULL tmp = a[j-M*L] - a[j-(M-1)*L]*base[L];
                --mp[tmp];
                if(mp[tmp] == 0) mp.erase(tmp);
                tmp = a[j] - a[j+L]*base[L];
                ++mp[tmp];
                if(mp.size() == M) ++ans;
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}


G - Mosaic

problem

think

自己写的二维线段树,开始T是因为,把update和query都写成一个函数了,导致if过多,拆成两个就A了, 

code

const int N = 810;
int n;
int a[N][N];
int mi[N<<2][N<<2];
int mx[N<<2][N<<2];
int L[N<<2];
int R[N<<2];
struct point{
    int a, b;
};
void build2(int l, int r, int k, int k1){
    if(L[k1] == R[k1] && l==r){
        mi[k1][k] = a[L[k1]][l];
        mx[k1][k] = a[L[k1]][l];
        return ;
    }
    if(l != r){
        int mid2 = (l+r) >> 1;
        build2(l, mid2, k<<1, k1);
        build2(mid2+1, r, k<<1|1, k1);
        mi[k1][k] = min(mi[k1][k<<1], mi[k1][k<<1|1]);
        mx[k1][k] = max(mx[k1][k<<1], mx[k1][k<<1|1]);
    } else {
        mi[k1][k] = min(mi[k1<<1][k], mi[k1<<1|1][k]);
        mx[k1][k] = max(mx[k1<<1][k], mx[k1<<1|1][k]);
    }
}
void build1(int l, int r, int k){
    L[k] = l;
    R[k] = r;
    if(l != r){
        int mid1 = (l+r) >> 1;
        build1(l, mid1, k<<1);
        build1(mid1+1, r, k<<1|1);
    }
    build2(1, n, 1, k);
}

point query2(int l2, int r2, int k2, int k1){
    if(l2 == L[k2] && r2 == R[k2]){
        point ans;
        ans.a = mi[k1][k2];
        ans.b = mx[k1][k2];
        return ans;
    }
    int mid2 = (L[k2] + R[k2]) >> 1;
    if(r2 <= mid2) return query2(l2, r2, k2<<1, k1);
    else if(l2 > mid2) return query2(l2, r2, k2<<1|1, k1);
    else{
        point ans1, ans2, ans;
        ans1 = query2(l2, mid2, k2<<1, k1);
        ans2 = query2(mid2+1, r2, k2<<1|1, k1);
        ans.a = min(ans1.a, ans2.a);
        ans.b = max(ans1.b, ans2.b);
        return ans;
    }

}

point query1(int l1, int r1, int k1, int l2, int r2, int k2){
    if(l1 == L[k1] && r1 == R[k1]) return query2(l2, r2, k2, k1);
    int mid1 = (L[k1] + R[k1]) >> 1;
    if(r1 <= mid1) return query1(l1, r1, k1<<1, l2, r2, k2);
    else if(l1 > mid1) return query1(l1, r1, k1<<1|1, l2, r2, k2);
    else{
        point ans1, ans2, ans;
        ans1 = query1(l1, mid1, k1<<1, l2, r2, k2);
        ans2 = query1(mid1+1, r1, k1<<1|1, l2, r2, k2);
        ans.a = min(ans1.a, ans2.a);
        ans.b = max(ans1.b, ans2.b);
        return ans;
    }
}

void update2(int k1, int l2, int k2, int val){
    if(l2 == L[k2] && l2 == R[k2]){
        if(L[k1] == R[k1]){
            mi[k1][k2] = val;
            mx[k1][k2] = val;
        } else {
            mi[k1][k2] = min(mi[k1<<1][k2], mi[k1<<1|1][k2]);
            mx[k1][k2] = max(mx[k1<<1][k2], mx[k1<<1|1][k2]);
        }
        return ;
    }
    int mid2 = (L[k2] + R[k2]) >> 1;
    if(l2 <= mid2) update2(k1, l2, k2<<1, val);
    else update2(k1, l2, k2<<1|1, val);
    mi[k1][k2] = min(mi[k1][k2<<1], mi[k1][k2<<1|1]);
    mx[k1][k2] = max(mx[k1][k2<<1], mx[k1][k2<<1|1]);
}

void update1(int l1, int k1, int l2, int k2, int val){
    if(l1 == L[k1] && l1 == R[k1]){
        update2(k1, l2, k2, val);
        return ;
    }
    int mid1 = (L[k1] + R[k1]) >> 1;
    if(l1 <= mid1) update1(l1, k1<<1, l2, k2, val);
    else update1(l1, k1<<1|1, l2, k2, val);
    update2(k1, l2, k2, val);
}

int main(){
    int T, tt = 0, m;
    scanf("%d", &T);
    while(T--){
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i) for(int j = 1; j <= n; ++j) scanf("%d", &a[i][j]);
        build1(1, n, 1);
        scanf("%d", &m);
        printf("Case #%d:\n", ++tt);
        while(m--){
            int x, y, d;
            scanf("%d%d%d", &x, &y, &d);
            d /= 2;
            int l1 = max(1, x - d);
            int r1 = min(n, x + d);
            int l2 = max(1, y - d);
            int r2 = min(n, y + d);
            point ans = query1(l1, r1, 1, l2, r2, 1);
            int res = (ans.a + ans.b) >> 1;
            printf("%d\n", res);
            update1(x, 1, y, 1, res);
        }
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值