2021 ICPC 江西省 A. Mio visits ACGN Exhibition(DP,大离谱,经验分享)

18 篇文章 0 订阅
13 篇文章 0 订阅

A. Mio visits ACGN Exhibition

分析:

  • D P   + DP\ + DP + 降维优化

  • f [ i ] [ j ] [ x ] [ y ] f[i][j][x][y] f[i][j][x][y] 表示从 ( 1 , 1 ) (1,1) (1,1) 走到 ( i , j ) (i,j) (i,j),经过 x x x 0 0 0 y y y 1 1 1 的方案数

    因为非 0 0 0 1 1 1 ( y = i + j − 1 − x ) (y=i+j-1-x) (y=i+j1x),故第四维可以直接去掉

    然后就可以得到:
    f [ i ] [ j ] [ x ] = { f [ i ] [ j − 1 ] [ x ] + f [ i − 1 ] [ j ] [ x ] ( a [ i ] [ j ] = 1 ) f [ i ] [ j − 1 ] [ x − 1 ] + f [ i − 1 ] [ j ] [ x − 1 ] ( a [ i ] [ j ] = 0 , x > 0 ) f[i][j][x]= \begin{cases} f[i][j-1][x]&+&f[i-1][j][x]&(a[i][j]=1)\\ f[i][j-1][x-1]&+&f[i-1][j][x-1]&(a[i][j]=0,x>0) \end{cases} f[i][j][x]={f[i][j1][x]f[i][j1][x1]++f[i1][j][x]f[i1][j][x1](a[i][j]=1)(a[i][j]=0,x>0)

  • 但是这是三维的,超空间了,还要再优化掉一维的空间,两种方法:

    • 滚动数组优化
    • p r e pre pre 存取 f [ i − 1 ] f[i-1] f[i1] 的所有状态

    f [ j ] [ x ] = { f [ j − 1 ] [ x ] + p r [ j ] [ x ] ( a [ i ] [ j ] = 1 ) f [ j − 1 ] [ x − 1 ] + p r [ j ] [ x − 1 ] ( a [ i ] [ j ] = 0 , x > 0 ) f[j][x]= \begin{cases} f[j-1][x]&+&pr[j][x]&(a[i][j]=1)\\ f[j-1][x-1]&+&pr[j][x-1]&(a[i][j]=0,x>0) \end{cases} f[j][x]={f[j1][x]f[j1][x1]++pr[j][x]pr[j][x1](a[i][j]=1)(a[i][j]=0,x>0)

三个坑点:

  • 预处理
  • i = 1   a n d   j = 1 i=1\ and\ j=1 i=1 and j=1 的情况要 c o n t i n u e continue continue
  • f [ j ] [ 0 ] = 0 f[j][0]=0 f[j][0]=0 (详见代码)

p r e pre pre 写法:

#include <bits/stdc++.h>
#define int long long
#define mod 998244353
using namespace std;

const int N=1005;
int a[N][N], f[N][N];
int pr[N][N];
signed main()
{
    int n,m,p,q;
    cin>>n>>m>>p>>q;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            cin>>a[i][j];
        }
    }
    if(!a[1][1]) f[1][1]=1;
    else f[1][0]=1; // 这就是预处理,我和队友枚举出来的预处理
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            for(int k=0;k<=i+j;k++)
            {
                pr[j][k]=f[j][k];
            }
        }
        for(int j=1;j<=m;j++)
        {
            if(i==1 && j==1) continue; //坑点二
            for(int k=0;k<=i+j-1;k++)
            {
                if(!a[i][j]) 
                {
                    f[j][k+1]=(f[j-1][k]+pr[j][k])%mod;
                }
                else f[j][k]=(f[j-1][k]+pr[j][k])%mod;
            }
			if(!a[i][j]) f[j][0]=0; // 坑点三,赛后还想了半年
        }
    }
    int ans=0;
    for(int i=p;i<=n+m-q-1;i++)
    {
        ans+=f[m][i];
        ans%=mod;
    }
    cout<<ans<<endl;
}

滚动数组写法:

#include <bits/stdc++.h>
#define mod 998244353
#define int long long
using namespace std;

const int N=1005;
int a[N][N], f[N][N];
signed main()
{
    int n,m,p,q;
    cin>>n>>m>>p>>q;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            cin>>a[i][j];
        }
    }
    if(!a[1][1]) f[1][1]=1;
    else f[1][0]=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++){
            if(i==1 && j==1) continue;
			for(int k=i+j-1;k>=0;k--)
			{
				if(a[i][j]) f[j][k]=(f[j-1][k]+f[j][k])%mod;
				else 
				{
					if(k) f[j][k]=(f[j-1][k-1]+f[j][k-1])%mod;
				}
			}
			if(!a[i][j]) f[j][0]=0;
        }
    }
    int ans=0;
    for(int i=p;i<=n+m-q-1;i++)
    {
        ans+=f[m][i];
        ans%=mod;
    }
    cout<<ans<<endl;
}

赛时复盘:

  • 由于队友开题太快,我第一题就开了这题,等队友签完三道题

    我也用 p r e pre pre 的方法,断断续续把这道题敲了个大概(趁队友放下键盘的间隙,抢过键盘~)

    然后就没有然后了… …

    我不会预处理!!?

    然后就和队友一起开始枚举预处理:

    先声明预处理的正解,以防你们被我们(我)带偏
    if(!a[1][1]) f[1][1]=1;
    else f[1][0]=1;
    
    No.1
        for(int i=0;i<=m;i++) f[i][0]=1;
    	一调,大了好多,没事,咱继续!
    No.2
    	for(int i=1;i<=m;i++) f[i][0]=1;
    	再调,还是大了,不过比刚才好一些,嗯,不错,有进步,继续!!
    No.3
    	f[0][0]=1;
    	再再调,还是大了,更接近答案了,胜利就在前方了!!!
    No.4
    	可能队友实在是看不下去我的沙雕操作了,让我跟他讲一下思路
    	然后他重新打了一遍,用的是滚动数组
    	然后也没有然后了
    	因为,他的答案小了... ... 
    	不过,细心的我还是一眼看到了他的预处理
    No.5
    	没错,队友的预处理是正解
    	然后,我就把队友的预处理偷了过来
    	然后,我过了样例!!!
    	"交不?"
    	"交!"
    	然后,就wa了第一发
    	就自闭了
    No.6
    	队友的滚动数组,过了样例!
    	"交了?"
    	"交!"
    	然后,wa了第二发
    No.7
    	10s later...
    	"你这个n+m-q为什么没-1?"
    	-1,再交(直接在牛客上改的)
    	然后,wa了第三发
    	队友成功自闭
    No.8
        我又从队友那里看到了一些不一样的东西,就是那句continue
    	偷过来,再交
    	然后,wa了第四发
    No.9
    	队友突然喊了一声"我是傻**"
    	然后加了一条代码
    	f[j][0]=0
    	然后,wa了第五发
    No.10
    	短暂的沉默
    	"这里还是没-1!"(指n+m-q)
    	再交,转啊转,"Accept!!!"
    

经验教训:

  • b u g bug bug 不要自己闷着头调,好歹也跟队友讲一下思路,让他们知道你在干啥
  • 要耐心去读队友的代码,帮队友 d e b u g debug debug,很多时候真是旁观者清!
  • 千万不要在在线编译器上直接改,否则 10 s 10s 10s 后就忘了
  • 心态一定不能崩!!!
  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yezzz.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值