19-11-2-M

最后一个当然要模自己辣。

%%%Miemengsb

ZJ一下:

三道题没有一道会的,唯一的20还是T2输出$n/2$得的

咝……

T1一看,只会暴力。

T2一看,像是状压,但是我是$dpsb$,于是弃掉了。

T3一看,GP不会,于是又打了一个暴力。

结果:

和*一样。

42
Miemeng 0
00:00:18
20
00:00:37
0
00:00:53
20
00:00:53

这是TJ:

我GP不会,于是先咕掉了,吱。

T2

非常不会的时光倒流状压dp。

首先设$f_{i,s}$为时间为$i$,状态是$s$时是否可行。

然后我们发现一个神奇的性质……

当我们手玩一下性质时,就会发现所谓的拨动传递抵消是没有用的,如果两个拨动传递的时候抵消了,那么一定有上面的所有祖先全部被拨动了$2$次(也就是没有拨动)。

我们从末情况向前推,每次的操作就变成去掉一个点的影响,我们预处理出每个点在$i$秒后的影响以实现快速转移。

为什么从末情况向前推更加优呢?

因为每个点的影响时间是确定的(倒着),如果正向的话就可能需要枚举或是处理最后时间的情况。

这样就可以快乐的转移了

#include <iostream>
#include <cstring>
#include <cstdint>
#include <climits>
#include <cstdio>
#define V 35
#define N 111
#define LL long long

using namespace std;

LL pn,tp,ans=INT_MAX;
LL fa[N],aim[N],aimn,
	g[V][V],dp[V][(1<<17)+V];

int main(){
#ifndef LOCAL
	freopen("decoration.in" ,"r",stdin);
	freopen("decoration.out","w",stdout);
#endif
	cin.sync_with_stdio(false);
	cin>>pn;
	fa[1]=0;
	for(int i=2;i<=pn;i++)
		cin>>fa[i];
	for(int i=1;i<=pn;i++){
		cin>>aim[i];
		if(aim[i]==1)
			aimn|=1<<(i-1);
	}
	LL maxs=(1ll<<pn)-1;
	for(int i=1;i<=32;i++){
		for(int j=0;j<=pn;j++){
			LL cnt=0,now=j,tot=pn-i;
			while(cnt<=tot && now!=0){
				cnt++;
				g[i][j]|=1<<(now-1);
				now=fa[now];
			}
		}
	}
	dp[pn+1][0]=1;
	for(int i=pn;i>=1;i--){
		for(int s=0;s<=maxs;s++){
			if(!dp[i+1][s]) continue;
			for(int k=1;k<=pn;k++)
				dp[i][s^g[i][k]]|=dp[i+1][s];
			dp[i][s]|=dp[i+1][s];
			if(dp[i][aimn]){
				cout<<pn-i+1<<endl;
				return 0;
			}
		}
	}
}

 

posted @ 2019-11-02 14:21  Miemeng_麦蒙  阅读(135)  评论(0编辑  收藏  举报

小麦在雨中,蒙蒙的雾气

麦蒙不想有人骚扰他,如果有必要 联系 QQ:1755601414

如果你嫌广告大,那就喷我吧,不是博客园的锅。