首页 > 其他分享 >[JSOI2018] 潜入行动 题解

[JSOI2018] 潜入行动 题解

时间:2024-10-15 21:59:26浏览次数:8  
标签:JSOI2018 题解 sum times int 潜入 监听器 big 监听

T6 [JSOI2018] 潜入行动

很套路、很裸的一道树形 DP。看了状态就会推方程的那种。

设 \(f_{u,i,0/1,0/1}\) 表示以 \(u\) 为根的子树中有 \(i\) 个监听器、\(u\) 有没有监听器、\(u\) 有没有被监听的方案数。

显然要枚举子节点 \(v\)、\(u\) 的监听器数量 \(i\)、\(v\) 的监听器数量 \(j\)。用 \(f_{u,i}\) 和 \(f_{v,j}\) 推出 \(f_{u,i+j}\)。

然后挨个推一下就完了。

若 \(u\) 不放,也没有被监听,则 \(v\) 必定不放,但根据题意 \(v\) 之前需要被监听。故:

\[f_{u,i+j,0,0}=\sum f_{u,i,0,0}\times f_{v,j,0,1} \]

若 \(u\) 放了,但没有被监听,则 \(v\) 必定不放,且 \(v\) 之前是否被监听无所谓。故:

\[f_{u,i+j,1,0}=\sum f_{u,i,1,0}\times(f_{v,j,0,0}+f_{v,j,0,1}) \]

若 \(u\) 不放,但被监听了,此时分两种情况:要么 \(u\) 原本就被监听了,则 \(v\) 放不放无所谓,但因为 \(u\) 没放所以 \(v\) 之前需要被监听;要么 \(u\) 原本没有被监听,则需要 \(v\) 来监听 \(u\),也就是 \(v\) 必须放,同时因为 \(u\) 没放所以 \(v\) 之前需要被监听。故:

\[f_{u,i+j,0,1}=\sum\big(f_{u,i,0,1}\times(f_{v,j,0,1}+f_{v,j,1,1})+f_{u,i,0,0}\times f_{v,j,1,1}\big) \]

若 \(u\) 放了,也被监听了,此时分两种情况:要么 \(u\) 原本没有被监听,则 \(v\) 必须放来监听 \(u\),而 \(v\) 原本是否被监听无所谓;要么 \(u\) 原本就被监听了,此时 \(u\) 的所有限制都被满足,则 \(v\) 的情况也是不限的。故:

\[f_{u,i+j,1,1}=\sum\big(f_{u,i,1,0}\times(f_{v,j,1,0}+f_{v,j,1,1})+f_{u,i,1,1}\times(f_{v,j,0,0}+f_{v,j,1,0}+f_{v,j,0,1}+f_{v,j,1,1})\big) \]

就没了。

坑点:

  1. 空间复杂度是 \(O(4nk)\) 的,而本题贴心地给你开了 \(\texttt{256MB}\) 的空间,所以只能开 int 数组;
  2. 转移方程中出现的 \(f_{u,i}\) 需要开一个临时数组存储,否则会造成后效性影响转移;
  3. 转移结束后再写 siz[u]+=siz[v]
#include<bits/stdc++.h>
#define fw fwrite(obuf,p3-obuf,1,stdout)
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
#define putchar(x) (p3-obuf<1<<20?(*p3++=(x)):(fw,p3=obuf,*p3++=(x)))
using namespace std;

char buf[1<<20],obuf[1<<20],*p1=buf,*p2=buf,*p3=obuf,str[20<<2];
int read(){
	int x=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x;
}
void write(int x,char sf='\n'){
	if(x<0)putchar('-'),x=~x+1;
	int top=0;
	do str[top++]=x%10,x/=10;while(x);
	while(top)putchar(str[--top]+48);
	if(sf^'#')putchar(sf);
}
using ll=long long;
constexpr int MAXN=1e5+5,MOD=1e9+7;
int n,k,head[MAXN],tot;
struct{int v,to;}e[MAXN<<1];
void addedge(int u,int v){
	e[++tot]={v,head[u]};
	head[u]=tot;
}
void add(int&x,int y){
	x=x+y>=MOD?x+y-MOD:x+y;
}
int dp[MAXN][105][2][2],siz[MAXN],tmp[105][2][2];
void dfs(int u,int fno){
	siz[u]=dp[u][0][0][0]=dp[u][1][1][0]=1;
	for(int i=head[u],v=e[i].v;i;i=e[i].to,v=e[i].v){
		if(v==fno)continue;
		dfs(v,u);
		for(int i=0;i<=min(siz[u],k);++i){
			tmp[i][0][0]=dp[u][i][0][0],dp[u][i][0][0]=0;
			tmp[i][0][1]=dp[u][i][0][1],dp[u][i][0][1]=0;
			tmp[i][1][0]=dp[u][i][1][0],dp[u][i][1][0]=0;
			tmp[i][1][1]=dp[u][i][1][1],dp[u][i][1][1]=0;
		}
		for(int i=0;i<=min(siz[u],k);++i)
			for(int j=0;j<=min(siz[v],k-i);++j){
				add(dp[u][i+j][0][0],(ll)tmp[i][0][0]*dp[v][j][0][1]%MOD);
				add(dp[u][i+j][1][0],(ll)tmp[i][1][0]*(((ll)dp[v][j][0][0]+dp[v][j][0][1])%MOD)%MOD);
				add(dp[u][i+j][0][1],((ll)tmp[i][0][1]*(((ll)dp[v][j][0][1]+dp[v][j][1][1])%MOD)%MOD+(ll)tmp[i][0][0]*dp[v][j][1][1]%MOD)%MOD);
				add(dp[u][i+j][1][1],((ll)tmp[i][1][0]*(((ll)dp[v][j][1][0]+dp[v][j][1][1])%MOD)%MOD+(ll)tmp[i][1][1]*(((ll)dp[v][j][0][0]+dp[v][j][0][1]+dp[v][j][1][0]+dp[v][j][1][1])%MOD)%MOD)%MOD);
			}
		siz[u]+=siz[v];
	}
}

int main(){
	n=read(),k=read();
	for(int i=1,u,v;i<n;++i){
		u=read(),v=read();
		addedge(u,v),addedge(v,u);
	}
	dfs(1,0);
	write((dp[1][k][0][1]+dp[1][k][1][1])%MOD);
	return fw,0;
}

标签:JSOI2018,题解,sum,times,int,潜入,监听器,big,监听
From: https://www.cnblogs.com/laoshan-plus/p/18468603

相关文章

  • [ABC213G] Connectivity 2 题解
    [ABC213G]Connectivity2题解套路的经典图上计数题。考虑枚举和\(1\)相连的子集\(S\)。答案显然由两部分构成,\(S\)集合和\(1\)相连的方案数\(f(S)\)和\(S\)对于\(G\)的补集所有的方案数\(g(S)\)。答案就是二者相乘。显然\(g\)更好处理。直接枚举集合的边即可......
  • P8386 [PA2021] Od deski do desk 题解
    P8386[PA2021]Oddeskidodesk题解考虑一个大的序列一定被分成几个区间来删除。朴素的dp定义是\(dp_{i,j}\)表示前\(i\)个数,最后一个数元素是\(j\)的方案数。然而这样不仅不好转移,而且设不下状态。不难发现所有值是等价的。考虑这样一个事情:若我们要分出一个新的区......
  • Project Euler 638 题解
    q-analog,老玩家集体起立!这也就是说:\[\binom{n+m}{n}_q=\sum_{\pi\inL_{n,m}}q^{area(\pi)}\]结束!#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongconstintmod=1e9+7,maxn=2e7+5;intqp(inta,intb,intp=mod){ intres=1; while(b){ i......
  • 2024某校新生校队选拔赛题解
    游记某校某院与某院联合培养机制给排了两场讲座,讲完吃饭,讲座时间\(8:00-12:00,\)拖堂\(10\)min,到食堂\(10\)min,吃饭\(30\)min,走回去\(10\)min,打开网址发现时间只够看榜的一看榜我草\(5\)小时连\(4\)个题都做不出来翻题面发现A,L纯签到,B半签到,遂确信成分题解题目链接A验证是......
  • Project Euler 457 题解
    初等数论小题目求\[n^2-3n-1\equiv0\pmod{p^2}\]配方,得到:\[(2n-3)^2\equiv13\pmod{p^2}\]根据亨泽尔引理,只需得到\((2n-3)^2\equiv13\pmod{p}\)的解即可提升到\(p^2\)。这是二次剩余,直接解。单次求解\(O(\logn)\),时间复杂度\(O(n)\)。#include<bits/stdc++.h......
  • TopCoder SRM616 ColorfulCoins 题解
    TopCoderSRM616ColorfulCoins题意给一套货币,保证任意两种货币存在倍数关系且颜色互不相同。已知货币的币值集合,每次可以询问一个金额,给出货币张数最小的表示方案。问最小的询问次数,使得通过已知信息可以对应货币面值和颜色。分析最大的面值问一个\(\inf\)即可。这时只需要......
  • [ABC062C]/[ARC074A] Chocolate Bar 题解
    神秘分讨题(?总共\(4\)中情况。第一种:三个竖的并列:ans=min(ans,(h%3>0)*w);。第二种:三个横的并列:ans=min(ans,(w%3>0)*h);。第三种:一个横的矩形,然后是两个竖着的。For(i,1,h){ intfst=i*w; intscd=(w/2)*(h-i); intthd=(w%2>0)*(h-i)+(w/2)*(h-i); ans=min(ans......
  • 堆排序题解
    给定一个整数序列,请按非递减序输出采用堆排序的各趟排序后的结果。输入格式:测试数据有多组,处理到文件尾。每组测试数据第一行输入一个整数n(1≤n≤100),第二行输入n个整数。输出格式:对于每组测试,输出若干行,每行是一趟排序后的结果,每行的每两个数据之间留一个空格。输入样例......
  • 「题解」Educational Codeforces Round 170 (Rated for Div. 2)
    before我不想写作业呜呜。A.TwoScreensProblemA.TwoScreensSol&Code理解题意后发现使用复制的方法完成最长公共前缀即可。#include<bits/stdc++.h>typedeflonglongll;typedefstd::pair<int,int>pii;intT;std::strings1,s2;intmain(){scanf("%d"......
  • CF1955G GCD on a grid 题解
    洛谷链接我们暴力枚举可能的答案\(k\),然后跑一边dp。设\(f_{i,j}\)表示在格子\((i,j)\)是否可以满足有一条路径可以到达该格子且该格子是否为\(k\)的倍数,递推式即为\(f_{i,j}=(k\mida_{i,j}\operatorname{and}(f_{i-1,j}\operatorname{or}f_{i,j-1}))\)最后的答......