在夜空所有星星熄灭的时候,所有梦|

Luckies

园龄:2年粉丝:1关注:1

2024-01-13 17:02阅读: 20评论: 0推荐: 0

AT_abc243_g [ABC243G] Sqrt题解

题目大意

有一个数列,初始时只有一个数 X。你可以对它进行一种操作:设末尾的数为 Y,从 1Y 中选一个数加到数列的末尾。如此进行 10100 次操作,问数列一共有多少种可能的状态。

解法

考虑 DP。

dpi 表示以数字 i 开头的数列可能的状态。设 i 的下一个位置上的数为 j,那么显然 dpi=j=1idpj。预处理出 dpi,询问时,答案为 dpx。但此时的时间复杂度为 Θ(T+XX),对于 X9×1018 这种极大的数据范围来说,显然是不可接受的,所以我们需要考虑优化。

j 的下一个位置上的数为 k,根据前面的转移方程,容易得出 dpj=k=1idpk。我们可以考虑算贡献。贡献是指 dpkdpj 的影响,也就是在所有的 dpj 中,有多少种状态含有 dpk。而 k 的范围是 1j,也就是 jkdpj 才会被 dpk 所影响,那么对于每一个 dpk,所能贡献的范围就是 k2i。这里的 i 就是所有 j 的范围。这样只需预处理出 dp1x4 的值,每次询问时,枚举 1x4,也就是 k,将所有 dpk 的贡献加起来即为答案。

这里有几点细节需要注意,由于此题数据范围过大,sqrt() 的精度可能不够,需要将开根的数强制转为 long double 才行。

AC Code

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 5;
int t, x, dp[N], f[N];
signed main()
{
dp[1] = 1;
for(int i = 2; i <= 1e5; i++)//预处理
for(int j = 1; j <= sqrt((long double)i); j++)
dp[i] += dp[j];
cin >> t;
while(t--)
{
cin >> x;
int y = sqrt((long double)x);
int ans = 0;
for(int i = 1; i <= sqrt((long double)y); i++)
ans += (y - i * i + 1) * dp[i];//dp[i]产生的贡献的范围是i * i ~ sqrt(sqrt(x))
cout << ans << "\n";
}
return 0;
}

本文作者:Luckies

本文链接:https://www.cnblogs.com/Luckies/p/17962592/AT_abc243_g

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Luckies  阅读(20)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起