牛客练习赛 68 D 牛牛的粉丝

牛牛的粉丝

https://ac.nowcoder.com/acm/contest/7079/D

题意:

在一个n个点环上,每个点有定量的人。
在接下来的k秒内,每一秒一个人每秒有一定概率往前走一步,往后走一步,或不动。
问最后每一个点上期望有多少人,答案均对 998244353 取模。

Sol

(998244353 emm... 居然没有人写多项式算法的题解呢)

首先对于每一个人在 k 秒后顺时针走多少步的概率是相同的。
我们把这个放在模n的意义下。设 表示一个人在模n意义下最后顺时针走了 步 的概率。
如果求出了这个那么可以直接 求出答案了,枚举起点终点然后用起点的人数乘上走的步数的概率加到终点的期望里即可。

那么怎么求呢?这个转移是个矩阵乘法,但是不加优化复杂度过高无法直接通过....
换一种思路,我们考虑用多项式解决。
容易的,我们可以构造这样的一个多项式来表示每一次的行走。

那么就是我们想要的。
但是我们的多项式并不支持 并且 k次方后的项数是巨大的。
不过早就说了这个是在模意义下,于是我们要求的多项式是这样的:

也就是一个循环卷积。直接倍增快速幂算循环卷积就行了。最后得到的 就是要求的 数组。
复杂度 比矩阵乘法优秀多了

#include<bits/stdc++.h>
using namespace std;
#define Set(a,b) memset(a,b,sizeof(a))
template<class T>inline void init(T&x){
  x=0;char ch=getchar();bool f=0;
  for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') f=1;
  for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch-48);
  if(f) x=-x;
  return;
}
typedef long long ll;
typedef double db;
const int mod=998244353,G=3,phi=998244352;
inline int fpow(int x,int k){int ret=1;for(;k;k>>=1,x=1ll*x*x%mod) if(k&1) ret=1ll*ret*x%mod;return ret;}
inline void Mod(int&x){if(x>=mod) x-=mod;else if(x<0) x+=mod;return;}
const int N=2000;
int rader[2000],F[N],T[N];int INV;
inline void Inc(int &x,int y){x+=y;if(x>=mod) x-=mod;}
inline void NTT(int *A,int n,int f)
{
  for(int i=1;i<n;++i) if(rader[i]>i) swap(A[i],A[rader[i]]);
  for(int i=1;i<n;i<<=1){
    int W=fpow(G,phi/(i<<1));
    if(f==-1) W=fpow(W,mod-2);
    for(int p=i<<1,j=0;j<n;j+=p){
      int w=1;
      for(int k=0;k<i;++k,w=1ll*w*W%mod){
    int X=A[j|k],Y=1ll*w*A[j|k|i]%mod;
    Mod(A[j|k]=X+Y);Mod(A[j|k|i]=X-Y);
      }
    }
  }
  if(f==-1) for(int i=0;i<n;++i) A[i]=1ll*A[i]*INV%mod;
  return;
}
int S[N],ans[N];
int main()
{
  int n;ll k;init(n),init(k);
  int a,b,c;init(a),init(b),init(c);
  int s=a+b+c;int invs=fpow(s,mod-2);
  for(int i=0;i<n;++i) init(S[i]);
  int p1=1ll*a*invs%mod;
  int p2=1ll*b*invs%mod;
  int p3=1ll*c*invs%mod;
  int up=-1,len=1;
  while(len<=(n<<1)) len<<=1,++up;
  INV=fpow(len,mod-2);
  for(int i=1;i<len;++i) rader[i]=(rader[i>>1]>>1)|((i&1)<<up);
  F[0]=1;
  T[0]=p3,T[1]=p1,T[n-1]=p2;
  while(k) {
    NTT(T,len,1);
    if(k&1) {
      NTT(F,len,1);
      for(int i=0;i<len;++i) F[i]=1ll*F[i]*T[i]%mod;
      NTT(F,len,-1);
      for(int i=0;i<n;++i) Inc(F[i],F[i+n]);
      for(int i=n;i<len;++i) F[i]=0;
    }
    k>>=1;
    for(int i=0;i<len;++i) T[i]=(ll)T[i]*T[i]%mod;
    NTT(T,len,-1);
    for(int i=0;i<n;++i) Inc(T[i],T[i+n]);
    for(int i=n;i<len;++i) T[i]=0;
  }
  for(int i=0;i<n;++i) {
    for(int j=0;j<n;++j) {
      int k=i-j;if(k<0) k+=n;
      Inc(ans[i],1ll*F[k]*S[j]%mod);
    }
    printf("%d ",ans[i]);
  }
  puts("");
}
全部评论

相关推荐

三年之期已到我的offer快到碗里来:9硕都比不上9本
点赞 评论 收藏
分享
评论
4
收藏
分享
牛客网
牛客企业服务