1. 程式人生 > 其它 >excel 讀寫

excel 讀寫

http://www.nfls.com.cn:10688/contest/536/problem/2

機器人 題解

令結點 x 上有\(a_x\)個不同的物品,題目要求每個連通塊的物品數之和的成績,就可以轉化成在每個連通塊內只選一個物品的方案數,因此,我們設計出dp。設\(f[u][i][j]\)表示以 u 為根的子樹,連通塊個數為 i,以及 u 縮在的連通塊內是否選過物品(\(j=0/1\))。

轉移時列舉\((u,v)\)並分成兩種情況,斷邊和不斷邊的情況,樹上揹包合併。注意,每一次合併的時候,等價於在包含 u 的子樹裡選不超過 k 個點,在包含 v 的子樹裡選擇不超過 k 兩個點,因為兩者的 dfs序 連續,所以每個節點最多與 4k 個結點合併,即 dfs序 上排在 u 之前的 2k 個和排在 u 之後的 2k 。然後轉移結束後,對於每個\(f[u][i][0]\)

都要乘上\(a_u\)轉移到\(f[u][i][1]\),表示選了結點 u 上的某個物品的情況。時間複雜度\(O(nk)\),雖然看上去是\(O(nk^2)\)

點選檢視程式碼
//CAN'T FORGET
//CAN'T FORGET
//CAN'T FORGET

//#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
#define _ 0
const long long maxn=4e4+5;
const long long maxm=1e6+5;
const long long mod=998244353;
const long long inf=0x3f3f3f3f;
inline long long read()
{
	long long x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-')
			f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*f;
}
struct node{
	long long to,nxt;
}edge[maxm];
long long head[maxm],tot;
void addedge(long long u,long long v)
{
	edge[++tot].to=v;
	edge[tot].nxt=head[u];
	head[u]=tot;
}
long long n,k;
long long a[maxn],sz[maxn],f[maxn][1005][2],dp[maxn][2];
void DP(long long x,long long y)
{
	for(long long a=1;a<=sz[x]&&a<=k;a++)
	{
		for(long long b=1;b<=sz[y]&&a+b-1<=k;b++)
		{
			dp[a+b-1][0]+=f[x][a][0]*f[y][b][0]%mod;
			dp[a+b-1][1]+=f[x][a][0]*f[y][b][1]%mod;
			dp[a+b-1][1]+=f[x][a][1]*f[y][b][0]%mod;
			
			dp[a+b-1][0]%=mod;
			dp[a+b-1][1]%=mod;
			dp[a+b-1][1]%=mod;
			if(a+b-1==k)
				break;
			dp[a+b][0]+=f[x][a][0]*f[y][b][1]%mod;
			dp[a+b][1]+=f[x][a][1]*f[y][b][1]%mod;
			dp[a+b][0]%=mod;
			dp[a+b][1]%=mod;
		}
	}
	sz[x]+=sz[y];
	for(long long i=1;i<=sz[x]&&i<=k;i++)
	{
		f[x][i][0]=dp[i][0];
		f[x][i][1]=dp[i][1];
		dp[i][0]=0;
		dp[i][1]=0;
	}
}
void dfs(long long x,long long fa)
{
	sz[x]=1;
	f[x][1][0]=1;
	for(long long i=head[x];i;i=edge[i].nxt)
	{
		long long y=edge[i].to;
		if(y==fa)
			continue;
		dfs(y,x);
		DP(x,y);
	}
	for(long long i=1;i<=sz[x]&&i<=k;i++)
	{
		f[x][i][1]+=f[x][i][0]*a[x]%mod;
		f[x][i][1]%=mod;
	}
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
//	freopen("robot.in","r",stdin);
//	freopen("robot.out","w",stdout);
    cin>>n>>k;
    for(long long i=1;i<=n;i++)
    	cin>>a[i];
    for(long long i=1;i<=n-1;i++)
    {
    	long long u,v;
    	cin>>u>>v;
    	addedge(u,v);
    	addedge(v,u);
	}
	dfs(1,0);
	cout<<f[1][k][1]<<endl;
	return ~~(0^_^0);
}
/*
Notes:
1.看所有題目
2.注意資料範圍
3.想想自己還能做什麼而不是做了什麼
4.看清題目!!!
5.記得把除錯程式碼刪掉!!!!
6.longlong時 1要寫成1ll
7.Think twice code once, think once code forever!
*/