分析:
体面看了好久
简单来说,就是有若干个同余方程
a0*k^0+a1*k^1+a2^k^2+…=x1
1<=k<=n,x1已知
求解ai
tip
再用高斯消元同余方程的时候
注意需要使用abs
有一句话的作用我搞不大懂
if (a[i][j]*a[j][i]<0) t=-t;
看来只能记住了
回带求值的过程在高斯消元解异或方程时是没有的
//回带求值
for (int i=n;i>=1;i--)
{
//解的情况的判断
if (a[i][i]==0&&a[i][n+1]%p!=0) return 0; //无解
else if (a[i][i]==0&&a[i][n+1]%p==0) continue; //自由元
//答案的处理
ans[i]=((a[i][n+1]*KSM(a[i][i],p-2))%p+p)%p;
//用第i个元素的答案,回带求解1~i-1
for (int j=i-1;j>=1;j--)
if (a[j][i])
a[j][n+1]-=a[j][i]*ans[i],
((a[j][n+1]%=p)+=p)%=p;
}
同余方程有一点好处,就是不用double,没有精度问题
但是还是需要注意随时%,因为有减操作,所以随时+p%p
//这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=100;
int p,a[N][N],n,ans[N];
int KSM(int a,int b)
{
a%=p;
int t=1;
while (b)
{
if (b&1)
t=(t%p*a%p)%p;
b>>=1;
a=(a%p*a%p)%p;
}
return t%p;
}
int gauss()
{
for (int i=1;i<=n;i++)
{
int num=i;
for (int j=i+1;j<=n;j++)
if (abs(a[j][i])>abs(a[num][i])) num=j;
//找到一行当前列的系数不为0
if (!a[num][i])
continue;
if (num!=i)
for (int j=1;j<=n+1;j++)
swap(a[i][j],a[num][j]);
for (int j=i+1;j<=n;j++)
if (j!=i&&a[j][i])
{
int t=((abs(a[j][i])%p*KSM(abs(a[i][i]),p-2)%p)%p+p)%p;
//系数化为一,除法变成乘法逆元
if (a[i][j]*a[j][i]<0) t=-t;
for (int k=1;k<=n+1;k++)
a[j][k]-=t*a[i][k],
((a[j][k]%=p)+=p)%=p;
}
}
//回带求值
for (int i=n;i>=1;i--)
{
//解的情况的判断
if (a[i][i]==0&&a[i][n+1]%p!=0) return 0;
else if (a[i][i]==0&&a[i][n+1]%p==0) continue;
//答案的处理
ans[i]=((a[i][n+1]*KSM(a[i][i],p-2))%p+p)%p;
//用第i个元素的答案,回带求解1~i-1
for (int j=i-1;j>=1;j--)
if (a[j][i])
a[j][n+1]-=a[j][i]*ans[i],
((a[j][n+1]%=p)+=p)%=p;
}
return 1;
}
int main()
{
int T;
scanf("%d",&T);
while (T--)
{
char s[N];
memset(a,0,sizeof(a));
scanf("%d",&p);
scanf("%s",&s);
n=strlen(s);
for (int i=0;i<strlen(s);i++)
if (s[i]=='*') a[i+1][n+1]=0;
else a[i+1][n+1]=s[i]-'a'+1;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
{
if (j==1)
{
a[i][1]=1;
continue;
}
a[i][j]=(a[i][j-1]*i)%p;
}
gauss();
for (int i=1;i<n;i++) printf("%d ",ans[i]);
printf("%d
",ans[n]);
}
return 0;
}