题解:P16125 [USTCPC 2026] Melody
lailai0916 · · 题解
题意简述
长度为
求所有合法序列的
解题思路
交换两层求和的顺序。枚举一种进行
固定
记
将固定位置按下标排序,记为
先考虑两个固定音符之间的一段。设相邻固定位置的距离为
展开这
若选中
若全部
记条件成立时
这正是代码中的 val。其中 u 为 v 为 d*i%k 是否等于端点差后,再决定是否加上 u。必须保留这项判断:全部转移被限制时,已经没有自由转移可以补足端点差。
再考虑首个固定位置之前和末个固定位置之后的两段。已知其中一端,每向外增加一个音符,都有一种选择的转移权值为
若
模数
排序需要
参考代码
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
using pii=pair<int,int>;
const int N=1000005;
const int mod=20120923;
int h[N];
pii a[N];
ll Pow(ll x,ll y)
{
x%=mod;
ll res=1;
while(y)
{
if(y&1)res=res*x%mod;
x=x*x%mod;
y>>=1;
}
return res;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin>>T;
while(T--)
{
int n,m,k;
cin>>n>>m>>k;
for(int i=0;i<k;i++)cin>>h[i];
for(int i=1;i<=m;i++)cin>>a[i].first>>a[i].second;
sort(a+1,a+m+1);
ll inv=Pow(k,mod-2),ans=0;
for(int i=0;i<k;i++)
{
ll c=(h[i]+mod-1)%mod;
ll res=Pow(c+k,m?n-1-a[m].first+a[1].first:n-1);
if(!m)res=res*k%mod;
for(int j=2;j<=m;j++)
{
int d=a[j].first-a[j-1].first;
ll u=Pow(c,d),v=Pow(c+k,d);
ll val=(v-u+mod)*inv%mod;
if(1LL*d*i%k==(a[j].second-a[j-1].second+k)%k)val=(val+u)%mod;
res=res*val%mod;
}
ans=(ans+res)%mod;
}
cout<<ans<<'\n';
}
return 0;
}