POJ 2065-SETI(高斯消元求解同余方程式)

题目地址:POJ 2065

题意:输入一个素数p和一个字符串s(只包含小写字母和‘*’),字符串中每个字符对应一个数字,'*'对应0,‘a’对应1,‘b’对应2....
           eg:str[] = "abc", 那么说明 n=3, 字符串所对应的数列为1, 2, 3。

           同时题目定义了一个函数:a0*1^0 + a1*1^1+a2*1^2+........+an-1*1^(n-1) = f(1)(mod p), f(1) = str[0] = a = 1;
                                    a0*2^0 + a1*2^1+a2*2^2+........+an-1*2^(n-1) = f(2)(mod p), f(2) = str[1] = b = 2;
                                    ..........
                                    a0*n^0 + a1*n^1+a2*n^2+........+an-1*n^(n-1) = f(n)(mod p),f(n) = str[n-1] = ````

         求出 a0,a1,a2....an-1。

思路:和POJ 2947很相像,只不过这道题的解是唯一确定的,也就是不需要判断无解和无穷解的情况,同时求i^(n-1)的时候用快速幂取余做,pow会溢出。

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <sstream>
#include <algorithm>
#include <set>
#include <queue>
#include <stack>
#include <map>
using namespace std;
typedef long long LL;
const int inf=0x3f3f3f3f;
const double pi= acos(-1.0);
const double esp=1e-6;
const int MAXN=110;
int aug[MAXN][MAXN];
int x[MAXN];
int m,n;
int gcd(int a,int b)
{
    int r;
    while(b!=0){
        r=b;
        b=a%b;
        a=r;
    }
    return a;
}
int lcm(int a,int b)
{
    return a/gcd(a,b)*b;
}
int Gauss(int mod)
{
    int i,j;
    int LCM;
    int ta,tb;
    int row,col,max_r;
    int tmp;
    for(row=0,col=0;row<m&&col<n;row++,col++){
        max_r=row;
        for(i=row+1;i<m;i++){
            if(abs(aug[i][col])>abs(aug[max_r][col]))
                max_r=i;
        }
        if(max_r!=row){
            for(j=row;j<n+1;j++)
                swap(aug[row][j],aug[max_r][j]);
        }
        if(aug[row][col]==0){
            row--;
            continue;
        }
        for(i=row+1;i<m;i++){
            if(aug[i][col]!=0){
                LCM=lcm(aug[i][col],aug[row][col]);
                ta=LCM/abs(aug[i][col]);
                tb=LCM/abs(aug[row][col]);
                if(aug[i][col]*aug[row][col]<0) tb=-tb;
                for(j=col;j<n+1;j++){
                    aug[i][j]=((aug[i][j]*ta-aug[row][j]*tb)%mod+mod)%mod;
                }
            }
        }
    }
    for(i=n-1;i>=0;i--){
        tmp=aug[i][n];
        for(j=i+1;j<n;j++){
            if(aug[i][j]!=0)
                tmp-=aug[i][j]*x[j];
            tmp=(tmp%mod+mod)%mod;
        }
        while(tmp%aug[i][i]!=0)
            tmp+=mod;
        x[i]=(tmp/aug[i][i])%mod;
    }
    return 0;
}
int pow_mod(int a,int n,int mod)
{
    int ans=1;
    while(n){
        if(n&1)
            ans=(ans*a)%mod;
        a=(a*a)%mod;
        n>>=1;
    }
    return ans;
}
int main()
{
    int T,p,i,j;
    char str[MAXN];
    scanf("%d",&T);
    while(T--){
        scanf("%d %s",&p,str);
        n=m=0;
        int len=strlen(str);
        for(i=0;i<len;i++){
            if(str[i]=='*')
                aug[i][len]=0;
            else
                aug[i][len]=str[i]-'a'+1;
            for(j=0;j<len;j++)
                aug[i][j]=pow_mod(i+1,j,p);
        }
        n=m=len;
        Gauss(p);
        for(i=0;i<len-1;i++)
            printf("%d ",x[i]);
        printf("%d\n",x[i]);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Rocky0429

一块也是爱

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值