POJ 2065 SETI 环上的高斯

题意:输入一个素数P,一串字符串str,字符串的每个字符对应一个整数a=1,b=2,c=3····,*=0(输入字符只会是26个小写字母加上*)。

例如str[] = "abc", 那么说明 n=3, 字符串所对应的数列为1, 2, 3。

并且题中定义了一个函数:

a0*1^0 + a1*1^1+a2*1^2+........+an-1*1^(n-1) = f(1), f(1) = str[0] = a = 1;
a0*2^0 + a1*2^1+a2*2^2+........+an-1*2^(n-1) = f(2), f(2) = str[1] = b = 2;
..........
a0*n^0 + a1*n^1+a2*n^2+........+an-1*n^(n-1) = f(n),f(n) = str[n-1] = ````

题解:注意,直接pow(i+1,j)容易溢出。

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;

const int MAXN = 100;
int a[MAXN][MAXN], x[MAXN];
int equ, var, P;

inline int gcd ( int a, int b )
{
    if ( b == 0 )
        return a;
    return gcd ( b, a % b );
}

inline int lcm ( int a, int b )
{
    return a * b / gcd ( a, b );
}

int mod_mult ( int a, int b, int n )
{
    int ret = 0;
    a = a % n;
    while ( b >= 1 )
    {
        if ( b & 1 )
        {
            ret = ret + a;
            if ( ret >= n ) ret -= n;
        }
        a = a << 1;
        if ( a >= n ) a -= n;
        b = b >> 1;
    }
    return ret;
}

int mod_exp ( int a, int b, int n )
{
    int ret = 1;
    a = a % n;
    while ( b >= 1 )
    {
        if ( b & 1 )
            ret = mod_mult(ret,a,n);
        a = mod_mult(a,a,n);
        b >>= 1;
    }
    return ret;
}

void Debug ()
{
    int i, j;
    for ( i = 0; i < equ; i++ )
    {
        for ( j = 0; j <= var; j++ )
            printf("%d ",a[i][j]);
        printf("\n");
    }
    printf("\n");
}

int Guass ()
{
    int i, j, row, col, mr;
    int ta, tb, l, tmp;
    row = col = 0;
    while ( row < equ && col < var )
    {
        mr = row;
        for ( i = row + 1; i < equ; i++ )
            if ( abs(a[i][col]) > abs(a[mr][col]) ) mr = i;

        if ( row != mr )
            for ( j = col; j <= var; j++ )
                swap ( a[row][j], a[mr][j] );
        if ( a[row][col] == 0 ) { col++; continue; }

        for ( i = row + 1; i < equ; i++ )
        {
            if ( a[i][col] == 0 ) continue;
            l = lcm ( abs(a[i][col]), abs(a[row][col]) );
            ta = l / a[i][col]; tb = l / a[row][col];
            if ( a[i][col] * a[row][col] < 0 ) tb = -tb;
            for ( j = col; j <= var; j++ )
                a[i][j] = ( (a[i][j]*ta-a[row][j]*tb) % P + P ) % P;
        }
        row++; col++;
    }
    for ( i = row; i < var; i++ )
        if ( a[i][var] != 0 ) return -1;
    if ( row < var ) return var - row;

    for ( i = var - 1; i >= 0; i-- )
    {
        tmp = a[i][var];
        for ( j = i + 1; j < var; j++ )
            tmp = ( (tmp-a[i][j]*x[j]) % P + P) % P;
        while ( tmp % a[i][i] != 0 ) tmp += P;
        x[i] = ( tmp / a[i][i] ) % P;
    }
    return 0;
}

int main()
{
    int t, i, j;
    char str[MAXN];
    scanf("%d",&t);
    while ( t-- )
    {
        scanf("%d %s",&P, str);
        equ = var = strlen(str);
        for ( i = 0; i < equ; i++ )
        {
            if ( str[i] == '*' ) a[i][var] = 0;
            else a[i][var] =  str[i] - 'a' + 1;

            for ( j = 0; j < var; j++ )
                a[i][j] = mod_exp(i+1,j, P);
        }
        //Debug();
        Guass();
        //Debug();

        for ( i = 0; i < var - 1; i++ )
            printf("%d ",x[i]);
        printf("%d\n",x[var-1]);
    }
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值