首页 > 其他分享 >[题解]CF1716D Chip Move

[题解]CF1716D Chip Move

时间:2024-06-24 12:36:46浏览次数:3  
标签:int 题解 Chip Move leq 步长 Theta 我们 dp

思路

Part 1

这种题目应该能一眼看出是 DP。

我们令 \(dp_{i,j}\) 表示走到 \(j\) 这个位置,最后一步花了 \(i\) 的倍数。

那么,我们的方程就很好想了:\(dp_{i,j} = \sum_{k = 1}^{j - k \times i \geq 0}dp_{i - 1,j - k \times i}\)。

因为,我们走到 \(j\) 的位置只能走 \(i\) 的倍数,所以我们上一步一定是走了 \(k \times i(k > 0)\) 的位置。又由于,我们的步长(即每一次的 \(i\))每一步都会加 \(1\),所以上一次状态的步长一定是 \(i - 1\)。

然后我们再利用一下前缀和即可。

但是,会有人对这个时间复杂度有所疑惑,这表面上是 \(\Theta(N^2)\) 的,实际上这有 \(\Theta(N \sqrt N)\)。

我们不难发现,我们要枚举的步长是会产生一个上限的。

假如在最不利的情况下,初始步长为 \(1\)。

因为,我们要满足 \((\sum_{i = 1}^{i \leq x}i) \leq N\)(其中,\(x\) 为满足条件的任意数,也就是我们程序中代码外层循环的次数)

由等差数列可知,\((\sum_{i = 1}^{i \leq x}i) = \frac{x(x + 1)}{2}\),因此,\(x \leq \sqrt {2N}\)。

综上,我们的时间复杂度为 \(\Theta(N \sqrt N)\)。

Part 2

虽然上述方法已经足矣通过此题,但是我们依旧可以对空间进行优化。

我们可以发现,每一次的状态只与它前面的位置有关,于是,我们只需要用前缀和记录上一个状态,再将新的状态覆盖到原位置上即可。

这样我们的空间复杂度由 \(\Theta(N \sqrt N)\) 降为了 \(\Theta(N)\)。

Code

#include <bits/stdc++.h>  
#define re register  
  
using namespace std;  
  
const int N = 2e5 + 10,mod = 998244353;  
int n,k,cnt;  
int s[N],ans[N];  
int dp[N] = {1};  
  
inline int read(){  
    int r = 0,w = 1;  
    char c = getchar();  
    while (c < '0' || c > '9'){  
        if (c == '-') w = -1;  
        c = getchar();  
    }  
    while (c >= '0' && c <= '9'){  
        r = (r << 3) + (r << 1) + (c ^ 48);  
        c = getchar();  
    }  
    return r * w;  
}  
  
int main(){  
    n = read();  
    k = read();  
    while (k <= n && cnt <= n){//需要判断总和是否大于 n   
        for (re int i = 0;i <= n;i++){  
            int t = (i - k >= 0 ? s[i - k] : 0);//需要判断一下是否越界   
            s[i] = (t + dp[i]) % mod;//更新前缀和 注意:这里的 dp[i] 还是未更新的值,所以请放心使用   
            dp[i] = t;//更新   
            ans[i] = (ans[i] + dp[i]) % mod;//每一次更新答案   
        }  
        cnt += k++;//每次更新总和   
    }  
    for (re int i = 1;i <= n;i++) printf("%d ",ans[i] % mod);  
    return 0;  
}  

标签:int,题解,Chip,Move,leq,步长,Theta,我们,dp
From: https://www.cnblogs.com/WaterSun/p/18264801

相关文章

  • [题解]CF1714F Build a Tree and That Is It
    思路由于题目中说这是一棵无根树,不太方便思考,于是,我们可以假装把这棵树看做有根树。首先我们令\(d_1,d_2,d_3\)分别表示从根节点到节点\(1,2,3\)的长度(不算相交部分)。那么我们可以得到下式:\[\left\{\begin{matrix}d_{12}=d_1+d_2\\d_{13}=d_1+d_3\\......
  • [题解]CF1712E1 LCM Sum (easy version)
    思路这是一道极好的思维题,主要考察了:组合数学和正难则反的方法。这题可以发现如果用直接法将十分的繁琐,于是乎,我们可以用正难则反的方法,即:总的减去不满足的。这道题总的很好求,为:\(C_{r-l+1}^{3}\)。不满足的情况,我们就可以将题目转化为:\(\operatorname{lcm}(i,j,k)<i+......
  • [题解]CF1712D Empty Graph
    思路因为我们枚举的直径是具备单调性的,所以可以使用二分答案。我们可以想一个事情,如果有两个点\(u\)和\(v\),它们两点之间的最短路径要么是直接从\(u\tov\);要么是经过一个中转点\(t\),即:\(u\tot\tov\)。然后,我们可以发现一个显然的规律,就是\(t\)一定是区间\(a\)中......
  • [题解]CF1704D Magical Array
    题意给定\(n\)个长度为\(m\)的数组,对于每一个数组选择下面任意一种操作进行若干次(操作二只能被一个数组选出)。\(c_{t,i}-1,c_{t,i-1}+1,c_{t,j}-1,c_{t,j-1}+1\)。\(c_{t,i}-1,c_{t,i-1}+1,c_{t,j}-1,c_{t,j-2}+1\)。最后输出选择操作二的数组......
  • [题解]CF1665E MinimizOR
    思路发现\(2^k\)大的数,最终的答案一定由前\(k+1\)小的元素组成。考虑数学归纳法,显然当\(k=1\)成立。假令\(k'\)时成立,证明\(k=k'+1\)时成立即可:若第\(k\)位有两个及以上的\(0\),显然最终答案的第\(k\)位一定为\(0\),因此考虑前面的\(k-1\)位,显然取......
  • [题解]CF1473D Program
    思路因为此题目中对于数的更新只能为\(1\),所以,如果我们找到了\([1,l-1]\)与\([r+1,n]\)中能获得的两个极值即可。我们为\(S\)赋予权值,用一个数组\(a\)储存:如果\(S_i\)为+,则其权值为\(1\)。否则其权值为\(-1\)。那么,在第\(i\)次操作后,能产生的数是\(\s......
  • [题解]CF1312E Array Shrinking
    思路本题为P3146变式,也算是一道很经典的区间DP题了。因为\(n\leq500\),考虑区间DP。定义\(dp_{i,j}\)表示操作\([i,j]\)区间剩余长度的最小值。那么,我们可以枚举一个中间值\(k\),可以显然地得到一个状态转移方程(即不能合二为一的情况):\[dp_{i,j}=\min(dp_{i,......
  • [题解]CF1223F Stack Exterminable Arrays
    CCF出的原题观摩一下。思路首先可以用一个Trie来维护。在这里对本文中的一些变量做一下说明。\(p\)表示当前维护的Trie中,指向的元素编号。\(t_i\)表示在Trie中编号为\(i\)的元素在原序列中的值。\(f_i\)表示在Trie中编号为\(i\)的元素在Trie中的父节点。......
  • [题解]CF1175E Minimal Segment Cover
    思路这是一道简单的DP题,DP题的核心就是状态转移。先来说一说\(dp\)数组的含义。\(dp_{i,j}\)表示从\(i\)这个点用\(2^j\)条线段能走到的最远的点。我们再来考虑一下边界情况。因为我们只用\(2^0\)条线段,那么:\(dp_{i,0}=\max(dp_{i,0},r)\)接着,我们递推一......
  • [题解]CF1092D1 Great Vova Wall (Version 1)
    思路发现,如果相邻元素的奇偶性相同,那么一定能通过在较低的位置竖着放若干个如果在\(i\)的位置竖着放一块砖头,使得这两列的高度相同。那么,我们想到直接考虑\(h_i\)的奇偶性,即将\(h_i\leftarrowh_i\bmod2\)。如果\(h_i=h_{i+1}\),我们显然可以同时使\(h_i\)和\(h......