D2. Up the Strip (Codeforces Round #740 (Div. 2))

D2. Up the Strip

https://codeforces.com/contest/1561/problem/D2

题目描述

有一个从 \(1\)\(n\)的单元格,你需要从 \(n\)走到 \(1\),当你处于单元格 \(x(1 <= x <= n)\)时,你有两种选择,

选择一个 \(y(1 <= y <= x-1)\),移动到 \(x-y\)的位置
选择一个 \(y(2 <= y <= x)\),移动到 \(\lfloor \frac ab \rfloor\)的位置

输出不同的方案数。

解题思路

首先这是一道动态规划题,同时可以想到 \(O(n^2)\)的转移方程: \(f(x) = \sum_{y=1}^{x-1}f(x-y) + \sum_{z=2}^xf(\lfloor \frac xz \rfloor)\)
前面部分的求和可以使用前缀和优化成 \(O(n)\)
后面的部分比较麻烦,首先可以想到整除分块,但是 \(O(n\sqrt n)\)复杂度对于 \(D2\)来说还是无法接受,
所以需要一个 \(O(nlog n)\)的算法,于是想到枚举倍数,即从 \(1\)\(n\)扫一遍,当考虑第 \(i\)位时,我们枚举 \(i\)的倍数 \({[2i,\lfloor \frac ni \rfloor * i]}\),即对于 \(j\)来说,如果 \(i*j <= n\),那么对于 \([i*j, (i+1) *j - 1]\)中的数除以 \(j\)答案都是 \(i\),所以需要用 \(f(i)\)来转移,所以我么只需要枚举 \(j(2 <= j <= \lfloor \frac ni \rfloor)\)即可,使用差分的思想在 \(i*j\)处加上 \(f(i)\)的贡献,在 \((i+1)*j\)处减去 \(f(i)\)的贡献,当处理到 \(x\)位置时需要差分数组求出 \(1 - x\)位置的前缀和即是后面部分的结果。

Code

#include <bits/stdc++.h>
#define ll long long
#define qc ios::sync_with_stdio(false); cin.tie(0);cout.tie(0)
#define fi first
#define se second
#define PII pair<int, int>
#define PLL pair<ll, ll>
#define pb push_back
using namespace std;
const int N = 4e6 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1e9 + 7;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
	while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
ll dp[N],sum,ans[N],m;

void solve(){
	int n;
	cin >> n >> m;
	dp[1] = 1;
	sum = 0;
	for(int i = 1; i <= n; i++){
		ans[i] += ans[i-1];
		ans[i] %= m;
		dp[i] += (sum + ans[i]) % m;
		for(ll j = 2; j * i <= n; j++){
			ans[i*j] += dp[i];
			ans[i*j] %= m;
			ans[min(i*j+j,n+1ll)] += (m - dp[i]) % m;
			ans[min(i*j+j,n+1ll)] %= m;
		}
		sum = (sum + dp[i]) % m;
	}
	cout << dp[n] << "\n";
}

int main()
{
	#ifdef ONLINE_JUDGE
	#else
		freopen("in.txt", "r", stdin);
		freopen("out.txt", "w", stdout);
	#endif

	qc;
	int T = 1;
	//cin >> T;
	while(T--){
		solve();
	}
	return 0;
}


posted @ 2021-08-25 10:38  !^^!  阅读(207)  评论(0)    收藏  举报