[HDU4658]Integer Partition

Description

T次询问,每次询问给出n,k,求将n划分成正整数之和,并且每个数的使用次数必须严格小于k的方案数。
n,k,t<=1e5

Solution

首先需要会基本的拆分数的姿势
然后对于这道题我们需要推一发:

Pk(x)=i=1(1+xi+x2i+x3i..+x(k1)i)

=i=11xki1xi

=ϕ(xk)ϕ(x)

=ϕ(xk)P(x)

于是我们可以先预处理出P(x),然后暴力求卷积。
显然 ϕ(xk) 只有 O(n) 项是有用的

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;

int read() {
    char ch;
    for(ch=getchar();ch<'0'||ch>'9';ch=getchar());
    int x=ch-'0';
    for(ch=getchar();ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
    return x;
}

void write(int x) {
    if (!x) {puts("0");return;}
    char ch[20];int tot=0;
    for(;x;x/=10) ch[++tot]=x%10+'0';
    fd(i,tot,1) putchar(ch[i]);
    puts("");
}

const int N=1e5+5,Mo=1e9+7;

int f[N];

void inc(int &x,int y) {x=x+y>=Mo?x+y-Mo:x+y;}

int Five(int x) {return (3*x*x-x)/2;}

void pre(int N) {
    f[0]=1;f[1]=1;
    fo(i,2,N) {
        for(int j=1;Five(j)<=i;j++) {
            inc(f[i],(j&1)?f[i-Five(j)]:Mo-f[i-Five(j)]);
            if (Five(-j)<=i) inc(f[i],(j&1)?f[i-Five(-j)]:Mo-f[i-Five(-j)]);
        }
    }
}

void solve(int n,int k) {
    swap(n,k);
    int res=f[n];
    for(int j=1;Five(j)*k<=n;j++) {
        inc(res,(j&1)?Mo-f[n-Five(j)*k]:f[n-Five(j)*k]);
        if (Five(-j)*k<=n) inc(res,(j&1)?Mo-f[n-Five(-j)*k]:f[n-Five(-j)*k]);
    }
    write(res);
}

int main() {
    pre(1e5);
    for(int ty=read();ty;ty--) solve(read(),read());
    return 0;
}

猜你喜欢

转载自blog.csdn.net/alan_cty/article/details/80187861