本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2023-04-09 12:13:23
纪念一下第一次不看题解,不看算法标签做出 CF 评分 2200。
虽然实际上最多提高组 T1。
G1 做法
G2 做法只需要在 G1 基础上稍微修改。
很自然想到设 $dp_{i,j}$ 表示第 $i$ 位是路径的第 $j$ 个点的方案数。
想一下如何转移,对于 $i = 1$,显然方案数是 $1$。
对于 $i \ge 2$,分一下类:
- 若 $i \equiv 1 \pmod k$,那么对于所有 $j \le i-1$,从 $dp_{j,i-1}$ 转移,颜色不用管。
- 否则,还要在情况 1 的基础上加上一条限制:第 $i$ 个点与 $j$ 点颜色相同。
主要思想就是这个。
关于怎么统计之前符合某些条件的状态答案综合,这个开个数组记一下就行了,都把 dp 设计出来了,这么简单的想必都会。
剩下的就是从大到小枚举 $m$,每次跑一遍 dp,找到答案就终止。
dp 复杂度 $O(n^2)$。
枚举最劣复杂度 $O(n)$。
总复杂度 $O(n^3)$。
Code
\/\/ LUOGU_RID: 107120197
#include <bits\/stdc++.h>
using namespace std;
#define FOR(i, a, b) for (int i = a; i <= b; i++)
#define REP(i, a, b) for (int i = a; i >= b; i--)
#define pb push_back()
#define mkpr make_pair
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int maxn = 5005;
typedef long long ll;
const ll mod = 1e9 + 7;
int t;
int n, k;
int c[maxn];
ll dp[maxn][maxn]; \/\/ 第 i 位状态为 j
ll sum[maxn][maxn]; \/\/ 颜色为 i,状态为 j,dp 值和
ll sum2[maxn]; \/\/ 状态为 i dp 总和
bool dp2[maxn][maxn],sum21[maxn][maxn],sum22[maxn];
inline int turn(int status)
{
if (status % k == 0)
return k;
return status % k;
}
int main()
{
scanf("%d", &t);
while (t--)
{
scanf("%d%d", &n, &k);
FOR(i, 1, n)
{
scanf("%d", &c[i]);
}
ll ans = 0;
FOR(i, 1, n)
{
dp2[i][1]=1;
FOR(j, 2, n)
{
if (turn(j) == 1)
{
dp2[i][j]|=sum22[j-1];
}
else
{
dp2[i][j]|=sum21[c[i]][j-1];
}
}
FOR(j, 1, n)
{
sum22[j] |= dp2[i][j];
sum21[c[i]][j] |= dp2[i][j];
}
}
int blocks = n \/ k;
bool isansoutputed=0;
for (int m = blocks * k; m > 0; m -= k)
{
bool flag = 0;
FOR(i, 1, n)
{
if (dp2[i][m])
{
flag = 1;
break;
}
}
if (flag)
{
\/\/ printf("m = %d\n", m);
FOR(i, 1, n)
{
dp[i][1] = 1;
FOR(j, 2, m)
{
if (turn(j) == 1)
{
dp[i][j] += sum2[j - 1];
}
else
{
dp[i][j] += sum[c[i]][j - 1];
}
dp[i][j] %= mod;
}
FOR(j, 1, m)
{
sum2[j] += dp[i][j];
sum2[j]%=mod;
sum[c[i]][j] += dp[i][j];
sum[c[i]][j] %= mod;
}
}
FOR(i, 1, n)
{
ans += dp[i][m];
ans%=mod;
FOR(j, 1, n)
{
\/\/ printf("dp[%d][%d] = %d\n",i,j,dp[i][j]);
dp[i][j] = 0;
sum[i][j] = 0;
}
sum2[i] = 0;
}
isansoutputed=1;
break;
}
}
if (!isansoutputed)
ans++;
printf("%lld\n", ans % mod);
FOR(i, 1, n)
{
sum2[i] = sum22[i]=0;
FOR(j, 1, n)
{
dp[i][j] = dp2[i][j]=0;
sum[i][j] = sum21[i][j]=0;
}
}
}
return 0;
}

鲁ICP备2025150228号