制限時間は1000ms
メモリ制限262144キロバイト
OSのWindows
感想
電車AK DLSゲームで、DPパラメータ言う、その後、彼は簡単に言ったとき、二日後、ああ、この問題について話した、シンプルなDPは逃げるトピックに住んでいるし、次への問題......
問題解決のためのアイデア
いくつかのリンクを投げ、それをダイジェスト
- https://blog.csdn.net/m0_43448982/article/details/96988882
- https://blog.csdn.net/Ratina/article/details/97237438
- https://www.cnblogs.com/zhuyou/p/11273721.html
おそらく設定\(DP [X] [Y ] [Z] [I] \) は以下の意味表現:スイープを前後、現在の掃引\を(私は\)グリッドは、最後の4つの色を表示する場合それらはあった(X、Y、Z、iは \)\の番号方式、\(私は\ X \ leqslant Y \ leqslantのZの\のleqslant)で、\(X、Y、Z、 iは\)を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\n",ans);
}
return 0;
}