CF-#Round84-div2-E题

CF-#Round84-div2-E题

E. Count The Blocks

传送门

这道题是逆元啦。
乘法逆元的运用。
CF不知怎么。炸了 今天晚上。

题目大意:给你一个数。问0~10^n-1(这些数位数不足包含前导0)的数中块的个数
块是这样定义的:长度为1的块代表有1个连续相同的数字
长度为2的块代表有2个连续相同的数字。。以此类推
输出。依次输出1~n的块有多少个

我们枚举一下可以发现:凡是给定的n,求n个连续相同的数字的个数一定是10。不会变。
当初我纠结了一下样例2。。
为啥所给的数字都没有达到180个。个数为1的块是怎么到达180个的。。后来发现没有正确理解块的含义。。emmm
我们计算的时候只需要计算个数为1的块有多少个就行。
直接拿总数减去2~n块的个数。
比如我们计算n=2的时候块为1的个数。
是把每个数字拆成一个一个一位数来看的。
所以我们求得2块数为10(这个是把两位数看成一个数,说起来有点绕hhh)
所以我们需要减去2倍
同理三位数需要减去3倍等等
然而n=2的时候把0~99看成一位数的话就有200个单独的数字。
式子是2*n^2;n=3,4,5…以此类推
所以我们求n = k时块为1的个数:
10^k * k - ans[2] * 2 - ans[3] * 3 - ans[k] * k;
为了代码处理方便。我们在代码处理部分相当于逆序存储了。
输出的时候逆序输出
ans[n]求得是块为1的个数
ans[1]求得是块为n得个数(一直是10.初始化的时候赋值为10)
代码部分直接将减去的部分作求和处理,存在sum中,之后直接减去就行了。
sum求解部分,需要累加:
p[]数组相当于前缀和的作用。累加。
sum = sum + ans[i] + p[i]
sum的值代表下一次需要减去的值:是上次处理的sum值+这次获取的ans[i](p[i]部分已经有一次ans[i]累加,因为下一次需要减去这次求得的两倍的ans[i],还要减去前面的ans[]值,各增加了一次,这里p[i]已经处理好了) + p[i](前面说的)
乘方处理用逆元噢。记得mod

代码部分:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 998244353;
const int N = 2e5 + 10;

ll n;
ll ans[N];
ll p[N];
ll sum;

ll npow(ll a, ll b)
{
	ll ans = 1;
	while (b)
	{
		if (b & 1)
		{
			ans = (ans * a) % mod;
		}
		a = (a * a) % mod;
		b >>= 1;
	} 
	return ans;
}

int main()
{
	cin >> n;
	ans[1] = 10;
	p[1] = 10;
	sum = ans[1] + p[1];
	for (ll i = 2; i <= n; i++)
	{
		ans[i] = (npow(10, i) * i % mod - sum + mod) % mod;
		p[i] = (p[i - 1] + ans[i]) % mod;
		sum = (sum + p[i] + ans[i]) % mod;
	}
	for (int i = n; i >= 1; i--)
	{
		cout << ans[i] << " ";
	} 	
	cout << endl;
	return 0;
}
发布了127 篇原创文章 · 获赞 3 · 访问量 3233

猜你喜欢

转载自blog.csdn.net/qq_44624316/article/details/105106643