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;
}
posted @ 2020-03-24 11:07  worcher  阅读(188)  评论(0编辑  收藏  举报