1. 程式人生 > 實用技巧 >luogu P4516 [JSOI2018]潛入行動

luogu P4516 [JSOI2018]潛入行動

LINK:潛入行動

初看題感覺很不可做 但是樹形dp的狀態過於明顯。

容易設\(f_{x,j,l,r}\)表示x為根子樹內放了j個裝置且子樹內都被覆蓋l表示x是否被覆蓋r表示x是否放裝置的方案數。

初值我是上面四個狀態都設為1 轉移分類討論一下也不困難。

然後需要容斥一下。

複雜度看起來是\(n\cdot k^2\)的 其實是\(n\cdot k\)的 證明 這個我就不口胡了。

當然還有一種轉移是隻給正確的狀態轉移 這樣就不需要容斥了 可能常數會小一點。

我常數比較大 開o2才能過 列舉的邊界注意把握好 這是TLE和AC的區別。

code
//#include<bits\stdc++.h>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<queue>
#include<deque>
#include<stack>
#include<vector>
#include<algorithm>
#include<utility>
#include<bitset>
#include<set>
#include<map>
#define ll long long
#define db double
#define INF 10000000000000000ll
#define ldb long double
#define pb push_back
#define put_(x) printf("%d ",x);
#define get(x) x=read()
#define gt(x) scanf("%d",&x)
#define gi(x) scanf("%lf",&x)
#define put(x) printf("%d\n",x)
#define putl(x) printf("%lld\n",x)
#define gc(a) scanf("%s",a+1)
#define rep(p,n,i) for(RE int i=p;i<=n;++i)
#define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
#define fep(n,p,i) for(RE int i=n;i>=p;--i)
#define vep(p,n,i) for(RE int i=p;i<n;++i)
#define pii pair<int,int>
#define mk make_pair
#define RE register
#define P 1000000007
#define gf(x) scanf("%lf",&x)
#define pf(x) ((x)*(x))
#define uint unsigned long long
#define ui unsigned
#define EPS 1e-4
#define sq sqrt
#define S second
#define F first
#define mod 1000000007
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
    RE int x=0,f=1;RE char ch=getc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}
const int MAXN=100002,maxn=102;
int n,len,lim,cc,ww;
int f[MAXN][maxn][2][2],sz[MAXN],g[maxn][2][2];
int lin[MAXN],nex[MAXN<<1],ver[MAXN<<1];
inline int mul(int x,int y){return (ll)x*y%mod;}
inline int add2(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline void add(int &x,int y){x=x+y>=mod?x+y-mod:x+y;}
inline int mus(int x,int y){return x-y<0?x-y+mod:x-y;}
inline void add1(int x,int y)
{
	ver[++len]=y;nex[len]=lin[x];lin[x]=len;
	ver[++len]=x;nex[len]=lin[y];lin[y]=len;
}
inline void dfs(int x,int fa)
{
	f[x][0][0][0]=f[x][1][0][1]=1;sz[x]=1;
	f[x][1][1][1]=f[x][0][1][0]=1;
	go(x)if(tn!=fa)
	{
		dfs(tn,x);
		rep(0,min(sz[x],lim),j)rep(0,1,l)rep(0,1,r)g[j][l][r]=f[x][j][l][r],f[x][j][l][r]=0;
		cc=min(sz[x],lim);
		rep(0,cc,j)
		{
			rep(0,sz[tn],k)
			{
				if(j+k<=lim)
				{
					add(f[x][j+k][0][0],mul(f[tn][k][1][0],g[j][0][0]));
					add(f[x][j+k][0][1],mul(add2(f[tn][k][0][0],f[tn][k][1][0]),g[j][0][1]));
					add(f[x][j+k][1][0],mul(add2(f[tn][k][1][1],f[tn][k][1][0]),g[j][1][0]));
					add(f[x][j+k][1][1],mul(add2(f[tn][k][1][0],f[tn][k][1][1]),g[j][1][1]));
					add(f[x][j+k][1][1],mul(add2(f[tn][k][0][1],f[tn][k][0][0]),g[j][1][1]));
				}
				else break;
			}
		}
		sz[x]+=sz[tn];
	}
	cc=min(sz[x],lim);
	rep(0,cc,j)f[x][j][1][0]=mus(f[x][j][1][0],f[x][j][0][0]),f[x][j][1][1]=mus(f[x][j][1][1],f[x][j][0][1]);
}
int main()
{
	//freopen("1.in","r",stdin);
	get(n);get(lim);
	rep(2,n,i)add1(read(),read());
	dfs(1,0);put(add2(f[1][lim][1][0],f[1][lim][1][1]));
	return 0;
}