• HDU 6578 Blank


    hdu题面

    Time limit 1000 ms

    Memory limit 262144 kB

    OS Windows

    Source 2019 Multi-University Training Contest 1

    感想

    火车上AK这场比赛的dls,在两天后直播讲题,讲到这题的时候,说得好轻松啊,一个简单的dp就完事了,然后说了一下dp的参数,然后就到下一题了……

    解题思路

    扔几个链接,融会贯通一下

    大概就是设(dp[x][y][z][i])代表如下的意思:从前向后扫,扫到目前第(i)个格子时,4种颜色最后出现的位置分别为(x、y、z、i)时的方案数,其中(xleqslant yleqslant zleqslant i),在(x、y、z、i)为0时取等号,表示目前有一些颜色还没有出现,即最后一次出现的位置为0。

    颜色种类不重要,因为计算过程已经把不同颜色的组合方式计算进去了,重要的是颜色的。然后染这一格((i))的时候的方案数是从染上一个格子((i-1))的方案数转移过来的。

    扩展当前这一个格子的时候,我们可以取之前出现过的4种颜色中的一种。举个例子,假设我们取的是之前最后一次出现在(x)的那个颜色,那么会发生这样的转移——(dp[y][z][i-1][i]+=dp[x][y][z][i-1])(想想dp数组四个参数的含义和大小关系,现在这个状态的数量增加了上一个状态的数量那么多种),取的是最后一次出现在(y)的那个颜色的话,发生的转移就是——(dp[x][z][i-1][i]+=dp[x][y][z][i-1]),同样的道理还有(dp[x][y][i-1][i]+=dp[x][y][z][i-1])(dp[x][y][i-1][i]+=dp[x][y][z][i])。对于判断条件,当我们跑完第(i)个格子的时候,就检查以(i)为右端点的所有条件,对于一个条件——([l,r])之间有(x)种颜色,我们可以看那些状态是否满足条件,看每个颜色最后一次出现的位置在区间内还是区间外,然后根据这个统计区间内颜色数量,不满足条件就把它们清零,防止转移到下一个(i)

    统计的时候就统计所有(i=n)的格子,把数量加起来就好。但是这种方法会爆空间,注意到(i)那一维可以滚动,所以把(i)那一维滚动起来。另外注意取模 993244853 998244353。

    源代码

    #include<vector>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    const int mod=998244353;
    
    int T;
    int n,m;
    long long dp[105][105][105][2];
    //x<y<z<i
    struct Condition{
    	int l,x;
    };
    std::vector<Condition> c[105];
    
    
    int main()
    {
    	//freopen("test.in","r",stdin);
    	scanf("%d",&T);
    	while(T--)
    	{
    		scanf("%d%d",&n,&m);
    		for(int i=0;i<105;i++) c[i].clear();
    		for(int i=1,l,r,x;i<=m;i++)
    		{
    			scanf("%d%d%d",&l,&r,&x);
    			c[r].push_back({l,x});
    		}
    		dp[0][0][0][0]=1;
    		int cur=1;//i&1
    		int last=0;//!(i&1)
    		for(int i=1;i<=n;i++)
    		{
    			for(int z=0;z<=i;z++)
    			{
    				for(int y=0;y<=z;y++)
    				{
    					for(int x=0;x<=y;x++)
    					{
    						dp[x][y][z][cur]=0;//清零
    					}
    				}
    			}
    			for(int z=0;z<i;z++)
    			{
    				for(int y=0;y<=z;y++)
    				{
    					for(int x=0;x<=y;x++)//转移
    					{
    						long long temp=dp[x][y][z][last];
    						dp[x][y][z][cur]+=temp;
    						dp[y][z][i-1][cur]+=temp;
    						dp[x][z][i-1][cur]+=temp;
    						dp[x][y][i-1][cur]+=temp;
    
    						dp[x][y][z][cur]%=mod;
    						dp[y][z][i-1][cur]%=mod;
    						dp[x][z][i-1][cur]%=mod;
    						dp[x][y][i-1][cur]%=mod;
    					}
    				}
    			}
    			for(unsigned int cc=0;cc<c[i].size();cc++)//判断
    			{
    				for(int z=0;z<i;z++)
    					for(int y=0;y<=z;y++)
    						for(int x=0;x<=y;x++)
    						{
    							int temp=1+(x>=c[i][cc].l?1:0)+(y>=c[i][cc].l?1:0)+(z>=c[i][cc].l?1:0);//统计区间内颜色数量
    							if(temp!=c[i][cc].x) dp[x][y][z][cur]=0;
    						}
    			}
    			std::swap(cur,last);
    		}
    		long long ans=0;
    		for(int z=0;z<n;z++)//统计答案
    		{
    			for(int y=0;y<=z;y++)
    			{
    				for(int x=0;x<=y;x++)
    				{
    					ans+=dp[x][y][z][last];
    					ans%=mod;
    				}
    			}
    		}
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    写日志文件
    内存文件映射应用举例『转』
    HOOK编程
    获取当前进程的名称
    C++实现FTP文件传输
    C/C++ 实现windows进程/线程/模块 遍历
    Unicode下的CString与char *转换
    MFC常用基本数据类型
    geos 3.6.1编译 win7 vs2015
    JQuery Mobile iscroll插件使用教程及注意事项
  • 原文地址:https://www.cnblogs.com/wawcac-blog/p/11318675.html
Copyright © 2020-2023  润新知