poj 2065 SETI(gauss--->≡)

题目链接
翻译链接

分析:
体面看了好久
简单来说,就是有若干个同余方程
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;
}
原文地址:https://www.cnblogs.com/wutongtong3117/p/7673067.html