解题思路
非常诡异的把一道数论题变成了图论题。。
首先把 i , i ∗ j i,i*j%mod i,i∗j之间连一条边,边权为 a b s ( i − j ) abs(i-j) abs(i−j),表示i能变成 i ∗ j i*j%mod i∗j,且所需代价为 a b s ( i − j ) abs(i-j) abs(i−j),然后成功让这题变成了图论题。
对于每个i跑一边 d i j + dij+ dij+堆优化( S P F A SPFA SPFA没爱了),就完了
代码
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
#define db double
using namespace std;
const ll mod=998244353;
int p,t,k,head[4000100],v[2010];
ll dis[2010],ans;
struct c{
int x,w,next;
}a[4000100];
void add(int x,int y,int w)
{
a[++k]=(c){y,w,head[x]};
head[x]=k;
}
priority_queue<pair<ll,int> > q;
void SPFA(int s){
while(!q.empty())q.pop();
for(int i=1;i<p;i++)
dis[i]=p,v[i]=0;
dis[s]=0;
q.push(make_pair(0,s));
while(!q.empty())
{
int x=q.top().second;
q.pop();
if(v[x])continue;
v[x]=1;
for(int i=head[x];i;i=a[i].next)
{
int y=a[i].x;
if(dis[y]>dis[x]+a[i].w)
{
dis[y]=dis[x]+a[i].w;
q.push(make_pair(-dis[y],y));
}
}
}
}
int main(){
scanf("%d%d",&p,&t);
for(int i=1;i<p;i++)
{
for(int j=i;j<min(p,i+18);j++)
add(i,i*j%p,j-i);
for(int j=max(1,i-18);j<i;j++)
add(i,i*j%p,i-j);
}
ll ksm=1;
for(int i=1;i<p;i++)
{
SPFA(i);
for(int j=1;j<p;j++)
{
ans=(ans+dis[j]*ksm%mod)%mod;
ksm=ksm*t%mod;
}
}
printf("%lld",ans);
}