ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[CF1716D]Chip Move 题解

2022-08-05 13:31:58  阅读:192  来源: 互联网

标签:cnt const int 题解 Chip long times CF1716D define


传送门QAQ

题目大意

一个数轴上,有一个芯片初始位置为 \(0\),它可以向右移动,第 \(i\) 次移动的距离必须是 \(k+i-1\) 的倍数,求走到 \(1\sim n\) 每个点的方案数。

\(1\le k \le n\le 2\times 10^5\)。

Preface

这道题真的后悔死了,场上就发现了性质,但优化没想出来,结果比赛一结束想出来了QAQ。

(写这篇文章时官方题解还没发布,这个方法是我自己 yy 出来的,可能比官方题解和别的大佬麻烦不少 qwq)

Analysis

首先会发现这题是一个 DP。

先把最简单朴素的 DP 列出来,然后再考虑优化:

令 \(f(i,j)\) 表示从 \(0\) 走 \(j\) 步到达点 \(i\) 的方案数。

初始状态:\(f(0,0)=1\)。

状态转移方程:\(f(i,j) =\sum\limits_{x=1}^{\lfloor \dfrac{i}{k+j-1} \rfloor} f(i-x\times (k+j-1),j-1)\)。

然鹅这样时空复杂度均无法接受,考虑优化。

我们会发现一个问题:从 \(0\) 走到 \(n\) 的最大步数似乎并不是特别多。

假设 \(k\) 取最小值 \(1\),每步走的距离都最近,设步数为 \(x\),则:

\(1+2+\ldots x= \frac{x(x+1)}{2} \le n\)。

这时会发现,最大步数是 \(O(\sqrt{n})\) 级别的,打个表列出来会发现最大也就 \(640\) 左右。

但是这么大的空间还是无法承受,并且我们上面的 DP 方程达不到 \(O(n\times 640)\)。

(考场上我在这里卡住了,结果一下考场就想出来了 qwq)

观察一下上面的状态转移方程,会发现方程的第一维,\(i,i-(k+j-1),i- 2\times(k+j-1)\ldots\) 这样写下去貌似有一些规律。

其实不难发现 \(i\equiv i-x\times (k+j-1) \pmod{(k+j-1)}\)。

那我们为什么要一点一点往前枚举呢?这完全可以直接开一个数组把前面的贡献全部存起来。

具体而言,令 \(cnt(x,y)= \sum\limits_{i\bmod (k+x)=y}f(i,x)\)。

初始状态:\(cnt(0,0)=1\)。

此时状态转移方程化为:\(f(i,j)= cnt(j-1,i \bmod (k+j-1))\)。

每次遍历完 \(i\),即将遍历 \(i+1\) 时再维护一下 \(cnt\) 数组即可。

即 \(cnt(j,i\bmod (k+j)) \gets cnt(j,i \bmod (k+j))+f(i,j)\)。

然鹅我们还要注意一下空间的问题,\(f\) 数组其实已经不是真正的 DP 数组了,可以把第一维直接省去。

但是 \(cnt\) 这两维还是很不好处理 o(╥﹏╥)o

此时就要充分发挥我们的乱搞精神,发现 \(k \le 2\times 10^4\) 的时候 \(cnt\) 还是开的下的,而 \(k\gt 2\times 10^4\) 时步数和转移次数至多为 \(10\),直接用我们最上面提到的朴素 DP 即可。

时间复杂度 \(O(n\sqrt{n})\),卡得比较紧,为了常数小一点不建议开 long long

Code

// Problem: D. Chip Move
// Contest: Codeforces - Educational Codeforces Round 133 (Rated for Div. 2)
// URL: https://codeforces.com/contest/1716/problem/D
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define Chtholly set<node>::iterator
#define SIT set<int>::iterator
#define VEC vector<int>::iterator
#define mp make_pair
#define fir first
#define sec second
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
const int mod = 998244353;
const int INF = 1e9;
const ll INFll = 1e16;
const int maxn = 2e5 + 5;
const int maxm = 3e6 + 5;
const int maxk = 1005;
int n,k;
int f[maxn],dp[maxn][15];
int cnt[maxk][maxk * 25];
void subtask() {
	dp[0][0] = 1;
	for(int i = 1;i < k;++ i) {
		printf("%d ",0);
	}
	for(int i = k;i <= n;++ i) {
		int ans = 0;
		for(int j = 1;j <= 10;++ j) {
			for(int x = 1;x <= i / (k + j - 1);++ x) {
				(dp[i][j] += dp[i - x * (k + j - 1)][j - 1]) %= mod;
			}
			(ans += dp[i][j]) %= mod;
		}
		printf("%d ",ans);
	}
	return ;
}
int main() {
	scanf("%d %d",&n,&k);
	if(k >= 20000) {
		subtask();
		return 0;
	}
	vector<int> G;
	int L[maxn];
	for(int cnt = 0,i = 0;cnt < n;) {
		cnt += k + i;
		++ i;
		G.pb(cnt);
	}
	for(int i = 1;i <= n;++ i) {
		L[i] = upper_bound(G.begin() , G.end() , i) - G.begin();
	}
	++ cnt[0][0];
	for(int i = 1;i <= n;++ i) {
		int ans = 0;
		for(int j = 1;j <= L[i];++ j) {
			f[j] = cnt[j - 1][i % (k + j - 1)];
			(ans += f[j]) %= mod; 
		}
		printf("%d ",ans);
		for(int j = 1;j <= L[i];++ j) {
			(cnt[j][i % (k + j)] += f[j]) %= mod;
		}
	}
	return 0;
}

完结撒花✿✿ヽ(°▽°)ノ✿

标签:cnt,const,int,题解,Chip,long,times,CF1716D,define
来源: https://www.cnblogs.com/663B/p/16553974.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有