【CF1558B】Up the Strip

时间:2021-08-25
本文章向大家介绍【CF1558B】Up the Strip,主要包括【CF1558B】Up the Strip使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

题目

题目链接:https://codeforces.com/problemset/problem/1558/B
你有一个正整数 \(n\),当 \(n>1\) 时,可以选择以下两种操作:

  1. 选择一个在 \([1,n)\) 范围内的整数 \(x\),让 \(n\) 减去 \(x\)
  2. 选择一个在 \([2,n]\) 范围内的整数 \(x\),让 \(n\) 除以 \(x\) 并下取整。

求有多少种方案使得 \(n\) 变为 \(1\)。答案对 \(m\) 取模。
\(n\leq 4\times 10^6\)\(m\) 是质数。(simplified version:\(n\leq 2\times 10^5\))。
时限 6s。

思路

\(f[i]\) 表示变到 \(i\) 的方案数。simplified version 的话由于 \(\lfloor\frac{i}{j}\rfloor\) 只有 \(O(\sqrt{i})\) 种取值,直接整除分块就可以了。时间复杂度 \(O(n\sqrt n)\)
而这道题的话就不考虑刷表,考虑如何转移到 \(f[i]\)。如果一个数除以 \(j\) 后下去整等于 \(i\),那么这个数的范围显然是 \([ij,(i+1)j-1]\)。那么直接枚举 \(j\),记一下后缀和即可。
时间复杂度 \(O(\sum_{i=1}^n \lfloor\frac{n}{i}\rfloor)=O(n\log n)\)

代码

/*
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2,tune=native")
*/
#include <bits/stdc++.h>
#define YES printf("YES\n")
#define Yes printf("Yes\n")
#define NO printf("NO\n")
#define No printf("No\n")
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;

const int N=4000010;
int Q,n,MOD,f[N],g[N];

int main()
{
	//cerr<<(sizeof(f)+sizeof(g))/1024/1024<<"\n\n";
	scanf("%d%d",&n,&MOD);
	f[n]=g[n]=1;
	for (int i=n-1;i>=1;i--)
	{
		f[i]=g[i+1];
		for (int j=2;i*j<=n;j++)
		{
			int l=i*j,r=min(n,(i+1)*j-1);
			if (l>r) continue;
			f[i]=((f[i]+g[l])%MOD-g[r+1])%MOD;
		}
		g[i]=(g[i+1]+f[i])%MOD;
	}
	cout<<(f[1]%MOD+MOD)%MOD;
	return 0;
}

原文地址:https://www.cnblogs.com/stoorz/p/15186302.html