这个菜鸡已经退役了,非常遗憾这份题解未能全部完成,只能咕咕咕咕咕~
Luogu链接
记下上次击打的时间,按照题意模拟即可。
#include
using namespace std;
inline int read()
{
int x=0,f=1;static char ch;
while(ch=getchar(),ch<48)if(ch==45)f=0;
do x=(x<<1)+(x<<3)+(ch^48);
while(ch=getchar(),ch>=48);
return f?x:-x;
}
int n,las[10],A,B;
int main()
{
n=read();
for(int i=1,t,a,b;i<=n;i++)
{
t=read(),a=read(),b=read();
if(las[a]&&t>=las[a]+1&&t<=las[a]+10)
{
las[a]=t;
if(a<=4)A+=150;
else B+=150;
}
else
{
las[a]=t;
if(a<=4)A+=100;
else B+=100;
}
}
printf("%d %d",A,B);
return 0;
}
Luogu链接
暴力的做法:爆搜 dfs(l,r,Ali,Bob)
表示当前剩余区间为 [ l , r ] [l,r] [l,r],Alice 和 Bob 取出的红色石头数目。每回合,轮到的人就枚举取两端的石头,若不存在一种取法使得自己必胜,对手必胜。按照这个思路可以写出:
bool dfs(int l,int r,int opt,int Ali,int Bob)// 返回1表示Alice必胜,返回0表示Bob必胜
{
if(opt)
{
if(Ali+a[l]<k&&dfs(l+1,r,0,Ali+a[l],Bob))return 1;
if(Ali+a[r]<k&&dfs(l,r-1,0,Ali+a[r],Bob))return 1;
return 0;
}
else
{
if(Bob+a[l]<k&&!dfs(l+1,r,1,Ali,Bob+a[l]))return 0;
if(Bob+a[r]<k&&!dfs(l,r-1,1,Ali,Bob+a[r]))return 0;
return 1;
}
}
容易发现有很多重复状态,于是用记忆化搜索。然而五维都设计进状态空间开不下,尝试去掉几维:
于是我们的状态就只剩 d p l , r , Ali dp_{l,r,\text{Ali}} dpl,r,Ali,成功解决了空间问题。最劣情况下每个状态到达一次,时间复杂度 O ( n 2 k ) O(n^2k) O(n2k)。
Luogu链接 loj链接
基环树 DP,简单又不简单。温馨提示:本做法处理环形 DP 时要分 24 类,请谨慎选择观看(
我们先用拓扑或其他方法找出环上的点,整颗基环树就被分为环和以环上的点为根的若干颗树。将 DP 分成旁边的若干颗树和环上进行处理,先来看看旁边的若干颗树怎么处理:
设计状态 d p x , c dp_{x,c} dpx,c 表示对于点 x x x,染色情况为 c c c 时子树中最少需要染色点数,不合法值为 i n f inf inf。染色情况分四类:
当 x x x 为叶子结点时,由于其没有儿子,故边界条件为 d p x , 0 = 0 dp_{x,0}=0 dpx,0=0, d p x , 1 = 1 dp_{x,1}=1 dpx,1=1。
当 x x x 为非叶子结点时,四种染色情况分别有如下转移:
d p x , 0 = ∑ v ∈ s o n x d p v , 1 d p x , 1 = ∑ v ∈ s o n x d p v , 1 + min v ∈ s o n x ( d p v , 3 − d p v , 1 ) d p x , 2 = 1 + ∑ v ∈ s o n x d p v , 0 d p x , 3 = 1 + ∑ v ∈ s o n x d p v , 0 + min v ∈ s o n x ( d p v , 2 − d p v , 0 ) \begin{aligned} dp_{x,0}=&\sum\limits_{v\in son_x}{dp_{v,1}}\\ dp_{x,1}=&\sum\limits_{v\in son_x}{dp_{v,1}} + \min\limits_{v\in son_x}{(dp_{v,3}-dp_{v,1})}\\ dp_{x,2}=&1+\sum\limits_{v\in son_x}{dp_{v,0}}\\ dp_{x,3}=&1+\sum\limits_{v\in son_x}{dp_{v,0}} + \min\limits_{v\in son_x}{(dp_{v,2}-dp_{v,0})} \end{aligned} dpx,0=dpx,1=dpx,2=dpx,3=v∈sonx∑dpv,1v∈sonx∑dpv,1+v∈sonxmin(dpv,3−dpv,1)1+v∈sonx∑dpv,01+v∈sonx∑dpv,0+v∈sonxmin(dpv,2−dpv,0)
转移解释如下:
对应代码如下:
int dp[M][4];
/*
0:自己不染儿子不染 -> 父亲必染
1:自己不染儿子染 -> 父亲必不染
2:自己染 儿子不染 -> 父亲必染
3:自己染 儿子染 -> 父亲必不染
*/
void dfs(int x,int fa)
{
bool flag=true;
for(int i=hd[x];i;i=e[i].nxt)
{
int v=e[i].to;
if(v==fa||on[v])continue;
dfs(v,x),flag=false;
}
if(flag)
{
dp[x][0]=0,dp[x][2]=1;// 没有儿子。自己染就是 1
return;
}
dp[x][0]=0,dp[x][2]=0;
for(int i=hd[x];i;i=e[i].nxt)
{
int v=e[i].to;
if(v==fa||on[v])continue;
dp[x][2]+=dp[v][0];// 儿子为0父亲必染
dp[x][0]+=dp[v][1];// 儿子为2父亲必染
}
for(int i=hd[x];i;i=e[i].nxt)
{
int v=e[i].to;
if(v==fa||on[v])continue;
dp[x][3]=min(dp[x][3],dp[x][2]-dp[v][0]+dp[v][2]);// 选一个儿子染
dp[x][1]=min(dp[x][1],dp[x][0]-dp[v][1]+dp[v][3]);// 选一个儿子染
}
dp[x][2]++,dp[x][3]++;// 最后再加,这样前面方便用
}
然后处理环上的 DP,常用手段是断环成链。依次记形成的链上的点为 1 … m 1\dots m 1…m 号点,我们枚举 1 1 1 号点的染色情况,便能推出顺理推出后续点的情况,最后得到合法的 m m m 号点的染色情况对应的染点数量。
设计状态 f i , j f_{i,j} fi,j 表示处理完环上前 i i i 个点,第 i i i 个点染色状态为 j j j 的最少染点。其中 i ≠ 1 i\ne 1 i=1, j j j 要分四类:
然后我们设 1 1 1 号点的染色情况为 c c c,我的垃圾写法需要分整整六类:
c c c | 1 1 1 号点 | 1 1 1 号点的儿子 | m m m 号点 |
---|---|---|---|
0 0 0 | 不染 | 不染 | 不染 |
1 1 1 | 不染 | 有且仅有一个染 | 不染 |
2 2 2 | 染 | 不染 | 不染 |
3 3 3 | 染 | 有且仅有一个染 | 不染 |
4 4 4 | 不染 | 不染 | 染 |
5 5 5 | 染 | 不染 | 染 |
注:根据题意可知 1 1 1 号点的儿子和 m m m 不能同时染,因此只有六种。
对于每一类,边界条件不同。这里建议自己画图,不然真的会弄晕:
c = 0 c=0 c=0:
f 2 , 0 = f 2 , 1 = inf f_{2,0}=f_{2,1}=\inf f2,0=f2,1=inf
解释:由于 1 1 1 号点的儿子以及 m m m 号点不染,那么 2 2 2 号点必染,因此 j j j 只能为 2 / 3 2/3 2/3。
f 2 , 2 = d p d 1 , 0 + d p d 2 , 2 f_{2,2}=dp_{d_1,0}+dp_{d_2,2} f2,2=dpd1,0+dpd2,2
f 2 , 3 = d p d 1 , 0 + d p d 2 , 3 f_{2,3}=dp_{d_1,0}+dp_{d_2,3} f2,3=dpd1,0+dpd2,3
解释:由于 1 1 1 号点及其儿子不染, 1 1 1 号点对应的 d p dp dp 染色情况为 0 0 0。由于 1 1 1 号点不染, 2 2 2 号点的 j j j 就由其对应 d p dp dp 染色情况决定。
c = 1 c=1 c=1:
f 2 , 2 = f 2 , 3 = inf f_{2,2}=f_{2,3}=\inf f2,2=f2,3=inf
解释:由于 1 1 1 号点的儿子有且仅有一个染,那么 2 2 2 号点必不染,因此 j j j 只能为 0 / 1 0/1 0/1。
f 2 , 0 = d p d 1 , 1 + d p d 2 , 0 f_{2,0}=dp_{d_1,1}+dp_{d_2,0} f2,0=dpd1,1+dpd2,0
f 2 , 1 = d p d 1 , 1 + d p d 2 , 1 f_{2,1}=dp_{d_1,1}+dp_{d_2,1} f2,1=dpd1,1+dpd2,1
解释:由于 1 1 1 号点不染,其有个儿子染, 1 1 1 号点对应的 d p dp dp 染色情况为 1 1 1。由于 1 1 1 号点不染, 2 2 2 号点的 j j j 就由其对应 d p dp dp 染色情况决定。
c = 2 c=2 c=2:
f 2 , 0 = f 2 , 1 = f 2 , 2 = inf f_{2,0}=f_{2,1}=f_{2,2}=\inf f2,0=f2,1=f2,2=inf
解释:由于 1 1 1 号点的儿子以及 m m m 号点不染,那么 2 2 2 号点必染。又因为 1 1 1 号点染,故 2 2 2 号点的儿子都必不染,因此 j j j 只能为 3 3 3。
f 2 , 3 = d p d 1 , 2 + d p d 2 , 2 f_{2,3}=dp_{d_1,2}+dp_{d_2,2} f2,3=dpd1,2+dpd2,2
解释:由于 1 1 1 号点染,儿子都不染, 1 1 1 号点对应的 d p dp dp 染色情况为 2 2 2。由于 2 2 2 号点染,儿子都不染, 2 2 2 号点对应的 d p dp dp 染色情况为 2 2 2。
c = 3 c=3 c=3:
f 2 , 0 = f 2 , 2 = f 2 , 3 = inf f_{2,0}=f_{2,2}=f_{2,3}=\inf f2,0=f2,2=f2,3=inf
解释:由于 1 1 1 号点的儿子有且仅有一个染,那么 2 2 2 号点必不染。又因为 1 1 1 号点染,故 2 2 2 号点的儿子都必不染,因此 j j j 只能为 1 1 1。
f 2 , 1 = d p d 1 , 3 + d p d 2 , 0 f_{2,1}=dp_{d_1,3}+dp_{d_2,0} f2,1=dpd1,3+dpd2,0
解释:由于 1 1 1 号点染,有个儿子染, 1 1 1 号点对应的 d p dp dp 染色情况为 3 3 3。由于 2 2 2 号点及其儿子都不染, 2 2 2 号点对应的 d p dp dp 染色情况为 0 0 0。
c = 4 c=4 c=4:
f 2 , 2 = f 2 , 3 = inf f_{2,2}=f_{2,3}=\inf f2,2=f2,3=inf
解释:由于 m m m 号点染,那么 2 2 2 号点必不染,因此 j j j 只能为 0 / 1 0/1 0/1。
f 2 , 0 = d p d 1 , 0 + d p d 2 , 0 f_{2,0}=dp_{d_1,0}+dp_{d_2,0} f2,0=dpd1,0+dpd2,0
f 2 , 1 = d p d 1 , 0 + d p d 2 , 1 f_{2,1}=dp_{d_1,0}+dp_{d_2,1} f2,1=dpd1,0+dpd2,1
解释:由于 1 1 1 号点不染,其有个儿子染, 1 1 1 号点对应的 d p dp dp 染色情况为 1 1 1。由于 1 1 1 号点不染, 2 2 2 号点的 j j j 就由其对应 d p dp dp 染色情况决定。
c = 5 c=5 c=5:
f 2 , 0 = f 2 , 2 = f 2 , 3 = inf f_{2,0}=f_{2,2}=f_{2,3}=\inf f2,0=f2,2=f2,3=inf
解释:由于 m m m 号点染,那么 2 2 2 号点必不染。又因为 1 1 1 号点染,故 2 2 2 号点的儿子都必不染,因此 j j j 只能为 1 1 1。
f 2 , 1 = d p d 1 , 2 + d p d 2 , 0 f_{2,1}=dp_{d_1,2}+dp_{d_2,0} f2,1=dpd1,2+dpd2,0
解释:由于 1 1 1 号点染,儿子都不染, 1 1 1 号点对应的 d p dp dp 染色情况为 2 2 2。由于 2 2 2 号点及其儿子都不染, 2 2 2 号点对应的 d p dp dp 染色情况为 0 0 0。
处理完边界条件后,我们开始转移:
f i , 0 = f i − 1 , 1 + d p d i , 0 f i , 1 = min ( f i − 1 , 3 + d p d i , 0 , f i − 1 , 1 + d p d i , 1 ) f i , 2 = f i − 1 , 0 + d p d i , 2 f i , 3 = min ( f i − 1 , 2 + d p d i , 2 , f i − 1 , 0 + d p d i , 3 ) \begin{aligned} f_{i,0}=&f_{i-1,1}+dp_{d_i,0}\\ f_{i,1}=&\min{\left(f_{i-1,3}+dp_{d_i,0},f_{i-1,1}+dp_{d_i,1}\right)}\\ f_{i,2}=&f_{i-1,0}+dp_{d_i,2}\\ f_{i,3}=&\min{\left(f_{i-1,2}+dp_{d_i,2},f_{i-1,0}+dp_{d_i,3}\right)} \end{aligned} fi,0=fi,1=fi,2=fi,3=fi−1,1+dpdi,0min(fi−1,3+dpdi,0,fi−1,1+dpdi,1)fi−1,0+dpdi,2min(fi−1,2+dpdi,2,fi−1,0+dpdi,3)
转移解释如下:
转移完了之后,我们该统计答案了。 1 1 1 号点的每种染色情况 c c c 都对应着 m m m 号点的固定染色情况:
在 1 1 1 号点的六种情况中取需染点的最小值,若仍大于 inf \inf inf 那么答案就为 − 1 -1 −1。
值得注意的是,有的状态可能没法从合法状态转移来。为了保证可读性,我们仍让 f f f 数组照常转移,但这时就可能出现 inf \inf inf 累加的情况。因此我们不能将 inf \inf inf 的值取得过大,定在 n + 1 n+1 n+1 是最合适的。
ans=inf;
//断环成链,枚举1号点的情况
for(int c=0;c<=5;c++)
{
if(c==0)
{
f[2][0]=f[2][1]=inf;
f[2][2]=dp[D[1]][0]+dp[D[2]][2];
f[2][3]=dp[D[1]][0]+dp[D[2]][3];
}
else if(c==1)
{
f[2][2]=f[2][3]=inf;
f[2][0]=dp[D[1]][1]+dp[D[2]][0];
f[2][1]=dp[D[1]][1]+dp[D[2]][1];
}
else if(c==2)
{
f[2][0]=f[2][1]=f[2][2]=inf;
f[2][3]=dp[D[1]][2]+dp[D[2]][2];
}
else if(c==3)
{
f[2][0]=f[2][2]=f[2][3]=inf;
f[2][1]=dp[D[1]][3]+dp[D[2]][0];
}
else if(c==4)
{
f[2][2]=f[2][3]=inf;
f[2][0]=dp[D[1]][0]+dp[D[2]][0];
f[2][1]=dp[D[1]][0]+dp[D[2]][1];
}
else
{
f[2][0]=f[2][2]=f[2][3]=inf;
f[2][1]=dp[D[1]][2]+dp[D[2]][0];
}
for(int i=3;i<=cnt;i++)
{
f[i][0]=f[i-1][1]+dp[D[i]][0];
f[i][1]=min(f[i-1][3]+dp[D[i]][0],f[i-1][1]+dp[D[i]][1]);
f[i][2]=f[i-1][0]+dp[D[i]][2];
f[i][3]=min(f[i-1][2]+dp[D[i]][2],f[i-1][0]+dp[D[i]][3]);
}
if(c==0)ans=min(ans,f[cnt][1]);
if(c==1)ans=min(ans,f[cnt][1]);
if(c==2)ans=min(ans,f[cnt][0]);
if(c==3)ans=min(ans,f[cnt][0]);
if(c==4)ans=min(ans,f[cnt][3]);
if(c==5)ans=min(ans,f[cnt][2]);
}
Luogu链接 loj链接
Luogu链接 loj链接