CF2150D 题解
做这题的时候读错了好几次题,生气了。
思路
首先,由于我们只关心位置数组的贡献和,位置数组之间的排列顺序我们是不关心的,所以我们将拍到桶里,设
然后我们可以发现,由于每一次移动的时候,表现为所有人向某一个位置集中,所以有人的位置一定是一个区间,表现在
我们通过手玩一下可以发现,每个一组
那么满足了这些要求的一定合法吗?
我们可以由最开始的数组进行考虑,从
现在我们得到了一些关于
虽然我们最终求的是所有位置数组的权值和,但是我们考虑,我们可以将所有去掉非零部分后一样的
端点处的奇偶性我们可以分类讨论,引入
所以我们可以对于
然后来处理权值和的部分。我们令区间长度为
这个东西很很可以前缀和啊,我们推一推式子。令
于是我们对
终于做完了。
Code
::::info[Code]
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
#define fi first
#define se second
using namespace std;
const int N=2e5+10;
const int inf=0x3f3f3f3f3f3f3f3f;
const int p=998244353;
int fpm(int a,int b)
{
int res=1;
while(b)
{
if(b&1) res=res*a%p;
a=a*a%p,b>>=1;
}
return res;
}
int fac[N<<1],inv[N<<1];
void init()
{
fac[0]=inv[0]=1;
for(int i=1;i<=4e5;i++) fac[i]=fac[i-1]*i%p,inv[i]=fpm(fac[i],p-2);
}
int C(int n,int m)
{
if(n<m) return 0;
return fac[n]*inv[m]%p*inv[n-m]%p;
}
int mod(int x)
{
while(x>=p) x-=p;
while(x<0) x+=p;
return x;
}
void add(int &x,int y)
{
x=x+y;
while(x>=p) x-=p;
while(x<0) x+=p;
}
int T;
int n,a[N],s[N];
void solve()
{
int ans=0;
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],add(ans,n*a[i]%p),add(a[i],a[i-1]);
for(int i=1;i<=n;i++) s[i]=mod(s[i-1]+a[i]);
for(int len=2;len<=n;len++)
{
for(int x=1;x<=2;x++) for(int y=1;y<=2;y++)
{
int tot=n-x-y-len+2;
if(tot<0||tot&1) continue;
int num=C(len+tot/2-1,len-1);
add(ans,num*mod(tot*fpm(len,p-2)%p+1)%p*mod(s[n]-s[len-1]-s[n-len])%p);
if(x==2) add(ans,num*a[n-len+1]%p);
if(y==2) add(ans,num*mod(a[n]-a[len-1])%p);
}
}
cout<<ans<<endl;
}
signed main()
{
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(false);
init();
cin>>T;
while(T--) solve();
return 0;
}
::::