8.16题解

T1

废物除了搜索啥都不会打,连个垃圾DP都推不出来,事实上知道他是DP之后,依旧打了很久,我的DP状态和大家都不太一样,比较清奇,不过我觉得很好想,$dp[i][j][k]$表示第$i$位上为$k$前一位上为$j$的方案数,$j$和$k$均在$0\thicksim3$的范围内,$0$ $1$ $2$参照题面,$3$代表此处有雷

思考

先来思考一下在大多数情况下那些方案对于相邻两位是合法的

00 两位上均没有雷且相邻位置上也没有雷
01 两位上均没有雷,后一个位置的相邻位置上有一个位置有雷,显然是右边
10 两位上均没有雷,前一个位置的相邻位置上有一个位置有雷,显然是左边
11 两位上均没有雷,且两个位置的相邻位置上都有一个位置有雷,显然左边一个右边一个
13 前一位上没雷,后一位上有雷
23 前一位左右两侧都有雷,后一位肯定是个雷
前一位是个雷,一共三种情况
31    32    33

初始化

由于$dp$定义的特殊性,我的初始化非常麻烦,直接初始化$dp[2]$,判断一下第一二位可能出现的情况,后面就直接从$dp[3]$开始转移即可

如果第一二位上均为$?$,那么我们只需要排除上面提到的9种情况中不合法的

10 上面有提到他需要前一位的左边有雷,但是第一位已经是最左,所以不合法
11 同上,第一位左侧不可能有雷
23 同上,左侧无雷

如果只有第一位是$?$,第二位已知直接就按照第二位,判断第一位可能情况即可

else if(a[1]==4)//4代表该处为?
{
    //当前为0,在上述的可能情况中选择,第一位只能为0
    if(a[2]==0)  dp[2][0][0]=1ll*1;
    //两种情况均可,对于前一种,第三位肯定是个3,当然,这是后话
    if(a[2]==1)  {dp[2][0][1]=1ll*1;  dp[2][3][1]=1ll*1;}
    //第二位为2,第一位肯定是个雷
    if(a[2]==2)  dp[2][3][2]=1ll*1;
    //第二位有个雷,第一位要么是个雷,要么不是雷那他的相邻位置上就必须标记有雷
    //注意23状态对于前两位,已经被判不合法
    if(a[2]==3)  {dp[2][1][3]=1ll*1;  dp[2][3][3]=1ll*1;}
}

同理判断只有第二位为$?$的情况,可以自己思考一下

else if(a[2]==4)
{
    if(a[1]==0)  {dp[2][0][0]=1ll*1;  dp[2][0][1]=1ll*1;}
    if(a[1]==1)  dp[2][1][3]=1ll*1;
    if(a[1]==3)  {dp[2][3][1]=1ll*1;  dp[2][3][2]=1ll*1;  dp[2][3][3]=1ll*1;}
}

两位都不为$?$要么不合法,要么就直接用,由于数据里没有不合法,所以我没判,严谨一点的话是需要判的

状态转移

当然又是一个长篇大论的分情况讨论,我们用$dp[i-1]$更新$dp[i]$

假设第$i$个位置上是0,由最初状态,状态只能是$00$或$10$,考虑这两种状态分别由哪些状态转移得来的,可以在列出的状态中选择合法状态,$00$可以由$00$和$10$转移得来,注意$dp[i]$的第二维和$dp[i-1]$的第三维之间的对应关系

第$i$个位置上为1,合法状态有$01$ $11$ $31$,$01$可以由$10$和$00$转移来,$11$由$31$转移来,$31$由$13$ $23$ $33$转移来

第$i$个位置为2或3时的状态转移可以自己想一想,想过之后去我的标程里对照一下,为5的时候就把前面的情况全和起来就可以了,我才不承认我是因为懒才没写全的

对于这种大量分情况讨论的题,转移的过程中一定要注意方案的合法性,保证补充不漏

统计答案

排除对最后一位来说的不合法状态即可

01 右侧不可能再出现雷
11 同上,右侧无雷
32 同上,右侧无雷
 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #define maxn 1001000
 5 #define ll long long
 6 #define mod 1000000007
 7 using namespace std;
 8 int n;
 9 ll ans;
10 int a[maxn];
11 char s[maxn];
12 ll dp[maxn][5][5];
13 int main()
14 {
15     scanf("%s",s);  n=strlen(s);
16     for(int i=1;i<=n;++i)
17     {
18         if(s[i-1]=='0')  a[i]=0;
19         else if(s[i-1]=='1')  a[i]=1;
20         else if(s[i-1]=='2')  a[i]=2;
21         else if(s[i-1]=='*')  a[i]=3;
22         else  a[i]=4;
23     }
24     if(a[1]==4&&a[2]==4)
25     {
26         dp[2][0][0]=1ll*1;  dp[2][0][1]=1ll*1;  dp[2][1][3]=1ll*1;
27         dp[2][3][1]=1ll*1;  dp[2][3][2]=1ll*1;  dp[2][3][3]=1ll*1;
28     }
29     else if(a[1]==4)
30     {
31         if(a[2]==0)  dp[2][0][0]=1ll*1;
32         if(a[2]==1)  {dp[2][0][1]=1ll*1;  dp[2][3][1]=1ll*1;}
33         if(a[2]==2)  dp[2][3][2]=1ll*1;
34         if(a[2]==3)  {dp[2][1][3]=1ll*1;  dp[2][3][3]=1ll*1;}
35     }
36     else if(a[2]==4)
37     {
38         if(a[1]==0)  {dp[2][0][0]=1ll*1;  dp[2][0][1]=1ll*1;}
39         if(a[1]==1)  dp[2][1][3]=1ll*1;
40         if(a[1]==3)  {dp[2][3][1]=1ll*1;  dp[2][3][2]=1ll*1;  dp[2][3][3]=1ll*1;}
41     }
42     else  dp[2][a[1]][a[2]]=1ll*1;
43     for(int i=3;i<=n;++i)
44     {
45         if(a[i]==0)
46         {
47             dp[i][0][0]=(dp[i-1][1][0]+dp[i-1][0][0])%mod;
48             dp[i][1][0]=dp[i-1][3][1];
49         }
50         else if(a[i]==1)
51         {
52             dp[i][0][1]=(dp[i-1][1][0]+dp[i-1][0][0])%mod;
53             dp[i][1][1]=dp[i-1][3][1];
54             dp[i][3][1]=((dp[i-1][1][3]+dp[i-1][2][3])%mod+dp[i-1][3][3])%mod;
55         }
56         else if(a[i]==2)
57             dp[i][3][2]=((dp[i-1][1][3]+dp[i-1][2][3])%mod+dp[i-1][3][3])%mod;
58         else if(a[i]==3)
59         {
60             dp[i][1][3]=(dp[i-1][0][1]+dp[i-1][1][1])%mod;
61             dp[i][2][3]=dp[i-1][3][2];
62             dp[i][3][3]=((dp[i-1][1][3]+dp[i-1][2][3])%mod+dp[i-1][3][3])%mod;
63         }
64         else
65         {
66             dp[i][0][0]=(dp[i-1][1][0]+dp[i-1][0][0])%mod;
67             dp[i][1][0]=dp[i-1][3][1];
68             dp[i][0][1]=(dp[i-1][1][0]+dp[i-1][0][0])%mod;
69             dp[i][1][1]=dp[i-1][3][1];
70             dp[i][3][1]=((dp[i-1][1][3]+dp[i-1][2][3])%mod+dp[i-1][3][3])%mod;
71             dp[i][3][2]=((dp[i-1][1][3]+dp[i-1][2][3])%mod+dp[i-1][3][3])%mod;
72             dp[i][1][3]=(dp[i-1][0][1]+dp[i-1][1][1])%mod;
73             dp[i][2][3]=dp[i-1][3][2];
74             dp[i][3][3]=((dp[i-1][1][3]+dp[i-1][2][3])%mod+dp[i-1][3][3])%mod;
75         }
76     }
77     ans=((ans+dp[n][0][0])%mod+dp[n][1][0])%mod;
78     ans=((ans+dp[n][3][1])%mod+dp[n][1][3])%mod;
79     ans=((ans+dp[n][2][3])%mod+dp[n][3][3])%mod;
80     printf("%lld\n",ans);
81     return 0;
82 }
超长分类讨论

T2

考试结束前三分钟,觉得可以和图论扯在一起,然而晚了

对于一个格子里水,他一定是沿着一条最矮的路流出去的,那么我们可以给相邻两点之间建边,以两点中的较大高度为边权,给最外面一圈点和外界连边,然后跑最小生成树,这样跑出来的就是最矮的一条路,也就是使所有点流出去的一条路,然后再$dfs$一遍,找到每个点流出去的路径上边权最大的边更新当前点的答案,因为一定是路径上最高的点限制了水流出去

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstdio>
 4 #define maxn 310
 5 #define bh(i,j) ((i-1)*m+j)
 6 using namespace std;
 7 struct node{
 8     int from,to,w;
 9 }a[maxn*maxn*4];
10 int n,m,tot,js;
11 int fa[maxn*maxn];
12 int head[maxn*maxn],to[maxn*maxn*8],xia[maxn*maxn*8],w[maxn*maxn*8];
13 int pd[maxn*maxn],ans[maxn*maxn];
14 int b[maxn][maxn];
15 int find(int x)
16 {
17     if(fa[x]!=x)  return fa[x]=find(fa[x]);
18     return fa[x];
19 }
20 void add(int x,int y,int z)
21 {
22     to[++js]=y;  xia[js]=head[x];  w[js]=z;  head[x]=js;
23 }
24 bool cmp(const node &a,const node &b)
25 {
26     return a.w<b.w;
27 }
28 void me(int x,int y)
29 {
30     x=find(x);  y=find(y);
31     fa[y]=x;
32 }
33 void dfs(int x)
34 {
35     pd[x]=1;
36     for(int i=head[x];i;i=xia[i])
37     {
38         int ls=to[i];
39         if(!pd[ls])  {ans[ls]=max(ans[x],w[i]);  dfs(ls);}
40     }
41 }
42 int main()
43 {
44 //    freopen("2.in","r",stdin);
45 //    freopen("WA.out","w",stdout);
46     scanf("%d%d",&n,&m);
47     for(int i=1;i<=n;++i)
48     {
49         for(int j=1;j<=m;++j)
50         {
51             scanf("%d",&b[i][j]);
52             if(i==1||i==n||j==1||j==m)
53                 {a[++tot].from=0;  a[tot].to=bh(i,j);  a[tot].w=max(0,b[i][j]);}
54             if(i-1>=1)
55             {
56                 a[++tot].from=bh(i-1,j);  a[tot].to=bh(i,j);
57                 a[tot].w=max(b[i][j],b[i-1][j]);
58             }
59             if(j-1>=1)
60             {
61                 a[++tot].from=bh(i,j-1);  a[tot].to=bh(i,j);
62                 a[tot].w=max(b[i][j],b[i][j-1]);
63             }
64         }
65     }
66     for(int i=0;i<=n*m;++i)  fa[i]=i;
67     int tt=0;
68     sort(a+1,a+tot+1,cmp);
69     for(int i=1;i<=tot;++i)
70     {
71         int fo=a[i].from,t=a[i].to;
72         if(find(fo)!=find(t))
73         {
74             me(fo,t);  add(fo,t,a[i].w);  add(t,fo,a[i].w);
75             tt++;
76             if(tt==n*m)  break;
77         }
78     }
79     for(int i=0;i<=n*m+10;++i)  ans[i]=-1000000100;
80     dfs(0);
81     for(int i=1;i<=n;++i)
82     {
83         for(int j=1;j<=m;++j)  printf("%d ",max(0,ans[bh(i,j)]-b[i][j]));
84         puts("");
85     }
86     return 0;
87 }
View Code

T3

莫比乌斯反演,咕了

posted @ 2019-08-18 06:16  hzoi_X&R  阅读(130)  评论(0编辑  收藏  举报