CF1327E Count The Blocks 简单计数

题面:

题意:
给定(n),求(0~10^n-1)中总共的连续相同长度块分别有多少个,例00032,有1个长度为3的连续块,2个长度为1的连续块
思路:
一个长度为k的块我们可以看作长度为(1)的块,其价值为(k)
(f[n]=9^{n-1}*10)表示连续(n)个长度为(1)的块的方案数
(ans[i]=sum_{j=2}^{n-i+1} j*f[j]*C_{n-i-1}^{j-2})
因为(1)个连续长度为(1)的块一定只能给价值(n),所以(j)(2)开始
(ans[i])相当于求价值为i的块的方案数
此时枚举连续(j)个长度为(1)的块,有(j)个位置可以放价值(i),所以乘上(j)
然后求将剩下价值(n-i)放入(j-1)个位置中,每个位置最少为(1)的方案数,即(C_{n-i-1}^{j-2}),乘上之前求出来的方案数
最后将所有枚举的j得到的方案数求和就是(ans[i])
但是这个做法时间复杂度怎么也得(O(n^2))级别的,肯定过不了
后来仔细思考发现,我想复杂了,实际上这题的计数并用不到组合数,而是简单计数,是线性的
考虑求ans[i],其相当于选择一个位置放只连续i个的相同的数,其他位置的数是什么并不重要
于是(ans[i]=2*10*9*10^{n-i-1}+(n-i-1)*10*9*9*10^{n-i-2})
前面的式子表示将只连续(i)个相同的放在头尾,那么需要一个间隔位置不同,所以(*9),其他位置随便,所以(*10^{n-i-1})
后面的式子表示将只连续(i)个相同的放在中间,那么需要两个间隔位置不同,所以(*9*9),其他位置随便,所以(*10^{n-i-2})
最后注意一下范围细节
代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<stack>
#include<queue>
#include<vector>
#include<cstring>
#include<string>
#include<map>
#define ll long long
#define mod 998244353 
using namespace std;
int n,ans;
int pw[200001];
int main()
{
    scanf("%d",&n);
    pw[0]=1;for(int i=1;i<=n;i++)pw[i]=(ll)pw[i-1]*10%mod;
    for(int i=1;i<=n;i++)
    {
      ans=0;
      if(i==n)ans=10;
      else ans=(ll)2*10*9*pw[n-i-1]%mod;
      if(n-i-2>=0)ans=((ll)ans+(ll)(n-i-1)*10*9*9*pw[n-i-2]%mod)%mod;
      printf("%d ",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/worcher/p/12557665.html