考虑求值的过程,容易发现我们会形成一颗\(k\)叉树,然后最后的总和是每个\(1\)点对应的深度的\(\frac{1}{k}\)次幂和。
容易发现在同一层有\(k\)个同样的点可以用下一层\(1\)个点代替并删除上面\(k\)个点,因此我们只要对任意\(n'\equiv n\pmod{k-1},m'\equiv m\pmod {k-1}\)的点对\((n',m')\)计数有\(\frac{n'+m'-1}{k-1}\)层,最上面一层有\(k\)个,以后每层\(k-1\)个,\(1\)的个数和为\(m'\),并且最上面一层不能同为一个数的方案数。容易dp转移,时间复杂度\(O(nm)\)。注意到外围的循环是\(O(\frac{n+m}{k})\)级别的,因此内层暴力\(O(k)\)转移复杂度也是对的。
code:
#include<bits/stdc++.h>
#define I inline
#define ll long long
#define db double
#define lb long db
#define N (2000+5)
#define M ((1<<14)+5)
#define K (700+5)
#define mod 1000000007
#define Mod (mod-1)
#define eps (1e-5)
#define ui unsigned int
#define ull unsigned ll
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((k+1)*(x)+(y))
#define R(n) (rnd()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;
int n,m,k;ll ToT,f[N],g[N];
int main(){
freopen("1.in","r",stdin);
int i,j;scanf("%d%d%d",&n,&m,&k);for(i=1;i<=(n+m-1)/(k-1);i++){
if(i==1) for(j=1;j<k;j++) f[j]=1;
else{Mc(g,f);Me(f,0);ll Ts=0;for(j=0;j<=m;j++) Ts+=g[j],j>k-1&&(Ts-=g[j-k]),f[j]=Ts%mod;}
for(j=m;j>0;j-=k-1) if(i*(k-1)+1-j<=n)ToT+=f[j];
}printf("%lld\n",ToT%mod);
}
标签:一层,frac,AT2294,AGC009E,Average,Eternal,long,复杂度,define
From: https://www.cnblogs.com/275307894a/p/16586594.html