Description
T次询问,每次询问给出n,k,求将n划分成正整数之和,并且每个数的使用次数必须严格小于k的方案数。
n,k,t<=1e5
Solution
首先需要会基本的拆分数的姿势
然后对于这道题我们需要推一发:
Pk(x)=∏i=1∞(1+xi+x2i+x3i..+x(k−1)i)
=∏i=1∞1−xki1−xi
=ϕ(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;
}