消元过程为保持整数用最小公倍数。
回代过程用线性模方程
计算过程注意保持模n下的非负数。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <set>
#include <algorithm>
#include <ctime>
#include <vector>
#include <string>
using namespace std;
int p,n;
char s[1000];
int a[100][100];
int ans[100];
int gcd(int a,int b)
{
return b==0 ? a : gcd(b,a%b);
}
int lcm(int a,int b)
{
return a/gcd(a,b)*b;
}
int extend_gcd(int a,int b,int &x,int &y)
{
if(b==0)
{
x=1;y=0;
return a;
}
int res=extend_gcd(b,a%b,y,x);
y=y-a/b*x;
return res;
}
void gauss()
{
for(int i=0;i<n;++i)
{
int pivot=i;
for(int k=i+1;k<n;++k)
if(abs(a[k][i])>abs(a[pivot][i]))
pivot=k;
if(a[i][i]==0)
continue;
if(pivot!=i)
{
for(int j=0;j<=n;++j)
swap(a[pivot][j],a[i][j]);
}
// elimination
for(int k=i+1;k<n;++k)
if(a[k][i])
{
int mul=lcm(a[i][i],a[k][i]);
int ma=mul/a[i][i];
int mb=mul/a[k][i];
for(int j=0;j<=n;++j)
a[k][j]=((a[k][j]*mb%p-a[i][j]*ma%p)%p+p)%p;
}
}
for(int i=n-1;i>=0;--i)
{
for(int k=i+1;k<n;++k)
{
a[i][n]-=a[i][k]*ans[k]%p;
a[i][n]=(a[i][n]%p+p)%p;
}
int x,y;
extend_gcd(a[i][i],p,x,y);
ans[i]=(x*a[i][n]%p+p)%p;
}
}
int main ()
{
int T;scanf("%d",&T);
while(T--)
{
scanf("%d%s",&p,s);
memset(a,0,sizeof(a));
n=strlen(s);
for(int i=1;i<=n;++i)
for(int t=1,j=0;j<n;++j,t*=i,t%=p)
a[i-1][j]=t;
for(int i=0;i<n;++i)
if(s[i]=='*')
a[i][n]=0;
else a[i][n]=s[i]-'a'+1;
gauss();
for(int i=0;i<n;++i)
{
printf("%d",ans[i]);
if(i<n-1)
printf(" ");
else puts("");
}
}
return 0;
}