GDOI2013 整数分拆

来源:互联网 发布:java返回值类型是类名 编辑:程序博客网 时间:2024/05/20 11:26

题目描述

题目要求求一个正整数n的分拆成k个数的方案。其中要求满足。
1a1+a2+...+ak=n
2a1b1a2
3a2b2a3

kak1bk1ak
其中b会读入。
n105,k10,bi1000.

解题思路

我们可以把原式改写:
a1=a1
a2=a1b1+x1
a3=a2b2+x2=a1b1b2+x1b2+x2

a1+a2+...+ak=n.
这样我把前面的k个等式带入最后的等式,就得到了一个只含有a1xi的方程,其中a11.求方程的解的个数就行了。

fi,j表示前i个未知数前i项的和为j的方案数。这样可以O(1)转移,总时间O(nk).

参考代码

#include<cstdio>#include<cstring>#include<iostream>#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--)#define maxn 100005#define maxk 15#define mo 1000000007#define mem(a,b) memset(a,b,sizeof(a))#define ll long longusing namespace std;int b[maxk],s[maxk];int T,n,k;int f[maxk][maxn];ll x[maxk];int main(){    scanf("%d",&T);    while (T--) {        scanf("%d%d",&n,&k);        fo(i,1,k-1) scanf("%d",&b[i]);        s[0]=1;        bool ok=0;        fo(i,1,k-1) {            s[i]=s[i-1]*b[i];            if (s[i]>n) {                ok=1;                break;            }        }        if (ok) {            puts("0");            continue;        }        mem(f,0);        fo(i,0,k-1) {            x[i]=1;            fo(j,i+1,k-1) {                x[i]+=s[j]/s[i];                if (x[i]>n) {                    x[i]=n+1;                    break;                }            }        }        fo(i,1,n / x[0])             f[0][i*x[0]]=1;        fo(i,1,k-1) {            fo(j,0,n) f[i][j]=f[i-1][j];            fo(j,x[i],n) f[i][j]=(f[i][j]+f[i][j-x[i]]) % mo;        }        printf("%d\n",f[k-1][n]);    }    return 0;}
1 0
原创粉丝点击