每周训练 题解

#A
从题目的第一行中可以很容易看出,这题用的是扩展欧几里得算法 i ∗ a + j ∗ b = n + 1 i*a+j*b=n+1 ia+jb=n+1,因为要保证 i ∗ a i*a ia, j ∗ b j*b jb为正整数,所以i,j必须为正整数。所以这题就求i,j的解为正整数的解的个数。没有看着来说明你对这个算法还不够了解。
求正整数解的个数的时候我是求出i的最小正整数解,再用i求出对应的j,接下来假设我们让i增加(i必然满足情况),那么j必然减小,所以让j除以j的每次的减少量,就可以直接的求出正整数解的个数。注意0不能取。

#include <bits/stdc++.h>
#define pi acos(-1)
#define pb push_back
#define LL long long
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
#define local freopen("in.txt","r",stdin)
#define input_fast std::ios::sync_with_stdio(false);std::cin.tie(0)
using namespace std;
const int mod = 1e9 + 7;
const int INF=0x7FFFFFFF;
inline void read(int& x){
    int flag = 1; char c; while(((c = getchar()) < '0' || c > '9') && c != '-');
    c == '-' ? (flag = -1, x = 0) : (x = c - '0');
    while((c = getchar()) >= '0' && c <= '9') { x = x * 10 + c - '0'; } x *= flag;
}

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

int main(){
    input_fast;
    //local;

    int t; LL n, a, b, d, x, y; cin >> t; while(t--){
        cin >> n >> a >> b; ++n;
        exgcd(a, b, d, x, y);
        if(n % d){ cout << 0 << endl; continue;}
        x *= n / d; x = (x % (b / d) + b / d) % (b / d);
        if(x == 0) x += b / d;
        y = (n - x * a) / b;
        if(y <= 0) cout << 0 << endl;
        else cout << y / (a / d) + (y % (a / d) ? 1 : 0) << endl;
    }
    return 0;
}

抛开这个题我们发现题目给的集合就是a,b都为1时的正整数解集,当a,b取不同值可能导致解集缩小(成为它的子集,虽然这样说不严谨),想想这个有助于你理解扩展欧几里得求通解的过程。
#B
N(n)就是[Partition](https://en.wikipedia.org/wiki/Partition_(number_theory)
我们从中发现了这里写图片描述这里写图片描述再结合题目中给的公式,就可以得出 x n x^n xn的系数序列为1,-1,-1,0,0,1,0,1···,而x的幂的取值为 k ( 3 k + 1 ) / 2 k(3k+1)/2 k(3k+1)/2,k为0,-1,1,-2,2···,具体工程看代码。

#include <bits/stdc++.h>
#define pi acos(-1)
#define pb push_back
#define LL long long
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
#define local freopen("in.txt","r",stdin)
#define input_fast std::ios::sync_with_stdio(false);std::cin.tie(0)
using namespace std;
const int INF = 0x7FFFFFFF;
const int mod = 1e9 + 7;
inline void read(int& x){
    int flag = 1; char c; while(((c = getchar()) < '0' || c > '9') && c != '-');
    c == '-' ? (flag = -1, x = 0) : (x = c - '0');
    while((c = getchar()) >= '0' && c <= '9') { x = x * 10 + c - '0'; } x *= flag;
}

int a[52000], cnt;
void init(){
    a[cnt++] = 0;
    for(int i = 1; true; ++i){
        a[cnt++] = (-i) * ((-i) * 3 + 1) / 2;
        if(a[cnt - 1] >= mod) break;
        a[cnt++] = i * (i * 3 + 1) / 2;
        if(a[cnt - 1] >= mod) break;
    }
    //cout << cnt << endl; 51641
}

LL power(LL a, int b){
    LL res = 1;
    while(b){
        if(b & 1) res = (res * a) % mod;
        a = a * a % mod; b >>= 1;
    }
    return res;
}

int main(){
    input_fast;

    init();
    int t, base, n, coe, index; LL ans = 0; read(t); read(base);
    for(int i = 1; i <= t; ++i){
        read(n);
        index = lower_bound(a, a + cnt, n) - a;
        if(a[index] == n){ if(index % 4 == 0 || index % 4 ==3) coe = 1; else coe = -1;}
        else coe = 0;
        if(coe == 1) ans = (ans + power(base, t - i)) % mod;
        else if(coe == -1) ans = (ans + 998244352 * power(base, t - i)) % mod;
    }
    cout << ans << endl;
    return 0;
}

#C
题解的证明,我还没有理解,大家先凑合看
题解
#D
这题我挂错了
#E
n堆糖果,每人可以从一堆中取任意多个(大于0)或者把一堆分成三堆,所以

sg(0)=0,
sg(1)=1,
sg(2)=2,
sg(3)=3



sg(7)=8;
sg(8)=7;
sg(9)=9;



sg(8k+1)=8k+1,
sg(8k+2)=8k+2,
.
.
.
sg(8k+7)=8k+8,
sg(8k+8)=8k+7,k>=0;
同样分成两堆的时候是
sg(4k+1)=4k+1,
sg(4k+2)=4k+2,
.
.
.
sg(4k+3)=4k+4,
sg(4k+4)=8k+3,k>=0;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值