HPUACM大二周练第一周

A

dfs暴力得到
{a[n]} ={1 1 2 2 4 4 6 6 10 10 14 14 20 20 26 26 36 36 46 46 60 60 74 74 94 94 114 114 140 140 166 166 202 202 238 238 284 284 330 330 390 390 450 450 524 524 598 598 692 692 ……}

发现对偶数项做差得到了原数列
{a[n]}={a[2k]a[2(k1)]}

那么就不难得到递推公式
a[i + 1] = a[i] = (a[i / 2] + a[i - 1]) % 1000000000;

注:下标都是从0开始的

#include<stdio.h>

int dp[1<<20] = {1,1,2,2,4,4};

void init() {
    for(int i = 4; i < 1<<20; i += 2) {
        dp[i + 1] = dp[i] = (dp[i / 2] + dp[i - 1]) % 1000000000;
    }
}

int main()
{
    init();
    int n;
    while(scanf("%d", &n) != EOF) {
        printf("%d\n", dp[n]);
    }
    return 0;
}

B

当然是xjb写了

#include<stdio.h>
#include<map>
#include<algorithm>
using namespace std;

int d[1<<16], w[1<<16], id[1<<16];
map<int, int> mp;
map<int,int>::iterator it;

int main()
{
    int n, m, sz = 1, x;
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; ++i) {
        scanf("%d", &x);
        if(mp[x]) continue;
        mp[x] = i;
    }
    it = mp.begin();
    while(it != mp.end()) {
        w[sz] = it->first;
        id[sz] = it->second;
        if(sz > 1 && id[sz] > id[sz - 1]) id[sz] = id[sz - 1];
        ++sz;
        it ++;
    }
    w[sz] = 1<<30;
    int use = n, ans = 0;
    for(int i = 0; i < m; ++i) {
        scanf("%d", &x);
        int pos = (int)(lower_bound(w, w + sz + 2, x) - w) - 1;
        if(use <= 0) continue;
        if(pos == 0) --use, ++ans;
        else if(pos == sz) use = 0;
        else {
            if(id[pos] > use) --use;
            else use = id[pos] - 2;
            if(use >= 0) ++ans;
        }
    }
    printf("%d\n", ans);
    return 0;
}

C

或运算是对于二进制而言的,我们考虑二进制即可
将所有数分两类:
一类是无论或上谁都不可能为x
一类是或运算后可能为x,我们考虑在这些数中去除最少个即可。

#include<stdio.h>
#include<algorithm>
using namespace std;

int cnt[2][63];

void add(long long n, int op) {
    for(int i = 0; i <= 62; ++i) {
        cnt[op][i] += n>>i&1;
    }
}

int main()
{
    int n;
    long long x, X;
    scanf("%d%lld", &n, &x);
    add(x, 0);
    X = x;
    for(int i = 0; i < n; ++i) {
        scanf("%lld", &x);
        if(!(x&~X)) add(x, 1);
    }
    int ans = 1<<30;
    for(int i = 0; i <= 62; ++i) {
        if(cnt[0][i])
            ans = min(ans, cnt[1][i]);
    }
    printf("%d\n", ans);
    return 0;
}

G

感觉会爆精度啊,然而并没有(我用了高精度模板,然而错了,不知道是不是模板问题)

#include<stdio.h>
typedef long long LL;

LL exGcd(LL a,LL b,LL &x,LL &y){
    if (b==0){
        x=1,y=0;
        return a;
    }
    LL q=exGcd(b,a%b,y,x);
    y-=a/b*x;
    return q;
}

LL CRT(int *m,int *a,int n){
    LL M=1,ans=0,x,t_i;
    for (int i=1;i<=n;i++) M*=m[i];
    for (int i=1;i<=n;i++){
        LL M_i=M/m[i];
        exGcd(m[i],M_i,x,t_i);     //求 M_i 模 m[i] 的逆元 t_i
        ans=(ans+a[i]*t_i%M*M_i%M)%M;
    }
    return (ans+M)%M;
}

int main()
{
    int n, x[1<<4], y[1<<4];
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) {
        scanf("%d %d", x + i, y + i);
    }
    LL ans = CRT(x, y, n);
    printf("%lld\n", ans);
    return 0;
}

(没写完,既然写了,就发出来

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值