题目描述
DP
很容易想到朴素DP
容易观察到DP数组有对称轴,而且中间一大段都是相等的,这个也易证。
于是就可以DP了。
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int maxn=100+10,maxm=10000+10,mo=1000000007;
int f[maxn][maxm],sum[maxn],num[maxm*2];
int h[maxn],go[maxn*2],next[maxn*2];
int i,j,k,l,r,t,n,m,tot,ca;
void add(int x,int y){
go[++tot]=y;
next[tot]=h[x];
h[x]=tot;
}
void dg(int x,int y){
int t=h[x],i;
fo(i,1,m) f[x][i]=0;
if (go[t]==y&&!next[t]){
fo(i,1,m) f[x][i]=1;
}
while (t){
if (go[t]!=y) dg(go[t],x);
t=next[t];
}
fo(i,1,m) num[i]=(num[i-1]+f[x][i])%mo;
sum[x]=num[m];
if (y){
fo(i,1,m){
t=(sum[x]-(num[min(m,i+k-1)]-num[max(i-k+1,1)-1])%mo)%mo;
if (!f[y][i]) f[y][i]=t;else f[y][i]=(ll)f[y][i]*t%mo;
}
}
}
void dfs(int x,int y){
int t=h[x],i;
fo(i,1,n*k) f[x][i]=0;
if (go[t]==y&&!next[t]){
fo(i,1,n*k) f[x][i]=1;
}
while (t){
if (go[t]!=y) dfs(go[t],x);
t=next[t];
}
fo(i,1,n*k) num[i]=(num[i-1]+f[x][i])%mo;
fo(i,n*k+1,n*k+k-1) num[i]=(num[i-1]+f[x][n*k])%mo;
sum[x]=num[n*k]*2%mo;
(sum[x]+=(ll)f[x][n*k]*((m-2*n*k)%mo)%mo)%=mo;
if (y){
fo(i,1,n*k){
t=(sum[x]-(num[i+k-1]-num[max(i-k+1,1)-1])%mo)%mo;
if (!f[y][i]) f[y][i]=t;else f[y][i]=(ll)f[y][i]*t%mo;
}
}
}
int main(){
freopen("label.in","r",stdin);freopen("label.out","w",stdout);
scanf("%d",&ca);
while (ca--){
scanf("%d%d%d",&n,&m,&k);
/*fo(i,1,n)
fo(j,1,min(m,n*k))
f[i][j]=0;*/
fo(i,1,n) sum[i]=h[i]=0;
tot=0;
fo(i,1,n-1){
scanf("%d%d",&j,&l);
add(j,l);add(l,j);
}
if (!k){
t=1;
fo(i,1,n) t=(ll)t*(m%mo)%mo;
printf("%d\n",t);
continue;
}
else if (m<=2*n*k) dg(1,0);else dfs(1,0);
(sum[1]+=mo)%=mo;
printf("%d\n",sum[1]);
}
}
本文介绍了一种利用对称轴特性的动态规划算法解决特定问题的方法。通过观察DP数组的对称性和中间部分的相等特性,文章提出了优化的DP实现方案,并给出了详细的C++代码实现。
1883

被折叠的 条评论
为什么被折叠?



