题目链接
https://www.lydsy.com/JudgeOnline/problem.php?id=5399
题解
打表观察序列,我们发现就是这个数在这个序列中出现的次数。
因此,如果我们暴力算出的前项的值,我们就可以求出的前项的值。
而序列是的前缀和,那么的含义就是的最大的。
考虑中每一项的含义。
就是的出现次数。
就是序列中最大为的位置。
那么就是序列中最大的等于的位置,即。
因此就是位置之前的每一段数的结尾位置的之和。
打表发现,可以边算边算这个。
代码
#include <cstdio>
int read()
{
  int x=0,f=1;
  char ch=getchar();
  while((ch<'0')||(ch>'9'))
    {
      if(ch=='-')
        {
          f=-f;
        }
      ch=getchar();
    }
  while((ch>='0')&&(ch<='9'))
    {
      x=x*10+ch-'0';
      ch=getchar();
    }
  return x*f;
}
const int maxm=1000000;
const int mo=998244353;
const int half=(mo+1)>>1;
int f[maxm+10];
int main()
{
  f[1]=1;
  for(int i=2; i<=maxm; ++i)
    {
      f[i]=f[i-f[f[i-1]]]+1;
    }
  int t=read();
  while(t--)
    {
      int n=read(),tot=0,g=0,i=1,res=0;
      while(tot+f[i]<=n)
        {
          int tmp=(2ll*tot+f[i]+1)%mo*f[i]%mo*half%mo;
          g=(g+1ll*tmp*i)%mo;
          res=(res+g)%mo;
          tot+=f[i++];
        }
      if(tot<n)
        {
          int tmp=(1ll*tot+n+1)%mo*(n-tot)%mo*half%mo;
          g=(g+1ll*tmp*i)%mo;
          res=(res+g)%mo;
        }
      printf("%d\n",res);
    }
  return 0;
} 
                    
                     
                    
                 
                    
                 
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号