poj 2065 SETI

SETI

题意:a0, a1, ...an-1 the function f (k) = ∑0<=i<=n-1aiki (mod p) always evaluates to values 0 <= f (k) <= 26 for 1 <= k <= n.

要求解的是a0, a1, ...an-1;其中 0 <= a0, a1, ...an-1 ,< P。

a0*10 + a1*11+a2*12+........+an-1*1(n-1)= f(1)

a0*20 + a1*21+a2*22+........+an-1*2(n-1) = f(2)

......

a0*n0 + a1*n1+a2*n2+........+an-1*n(n-1) = f(n)

PS:要是看我前面Widget Factory 会发现里面exgcd(a,b,...)在这道题中是个坑。。因为a,b不一定全是正数,并且只要有一个是负数,值正好就是负数(原理同gcd());所以在exgcd()之前把a[i][i]化为正数。还有前面化为上三角阵LCM处求解系数时分母没有加上abs()也是个坑。现已修改~~(no zuo no die!!)

思路:和Widget Factory 一样,题目没讲清楚是否一定有解,但是输入的数据确实是有唯一解的;(我试了不测试Gauss()的返回值也A了);PS:29983是测试过的素数,可以自己生成字符串来对拍一下(其实我只是从文件输入就发现用大素数测试对WA很有效)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
#include<stdlib.h>
#include<time.h>
using namespace std;
#define rep0(i,l,r) for(int i = (l);i < (r);i++)
#define rep1(i,l,r) for(int i = (l);i <= (r);i++)
#define rep_0(i,r,l) for(int i = (r);i > (l);i--)
#define rep_1(i,r,l) for(int i = (r);i >= (l);i--)
#define MS0(a) memset(a,0,sizeof(a))
#define MS1(a) memset(a,-1,sizeof(a))
template <typename T>
T abs(T a){return a < 0 ? -a:a;}
template <typename T>
T min(T a,T b){return a < b?a:b;}
template <typename T>
T max(T a,T b){return a < b?b:a;}
typedef __int64 ll;
ll a[72][72],x[80];
int equ,var,MOD;
void debug()
{
    puts("********");
    int i,j;
    rep0(i,0,equ){
        rep1(j,0,var)
            cout<<a[i][j]<<" ";
        cout<<endl;
    }puts("********");
}
int __gcd(int a,int b)
{
    return b?__gcd(b,a%b):a;
}
int LCM(int a,int b)
{
    return a/__gcd(a,b)*b;
}
void exgcd(int a,int b,int& d,int& x,int& y)
{
    if(!b){d = a;x = 1;y = 0;}
    else{
        exgcd(b,a%b,d,y,x);
        y -= x*(a/b);
    }
}
int Gauss()
{
    int i,j,k,free_var = 0,row,col;
    for(row = 0,col = 0;row < equ && col < var;row++,col++){
        int mx = row;
        rep0(j,row+1,equ)
            if(abs(a[j][col]) > abs(a[mx][col]))  mx = j;
        if(a[mx][col] == 0){
            row--;  // 行不变;不能通过这里记录自由变元的个数,只能记录没用的col
            continue;
        }
        if(mx != row)
            rep1(k,col,var)
                swap(a[row][k],a[mx][k]);
        rep0(j,row+1,equ){
            if(a[j][col] != 0){
                ll lcm = LCM(abs(a[row][col]),abs(a[j][col]));
                ll ration_row = lcm/abs(a[row][col]),ration_j = lcm/abs(a[j][col]);
                if(a[row][col]*a[j][col] < 0) ration_row = -ration_row; //符号相反变加法;
                rep1(k,col,var)
                    a[j][k] = (a[j][k]*ration_j - a[row][k]*ration_row)%MOD;
            }
        }
    }
    //debug();
    rep0(i,row,equ)
        if(a[i][var] != 0) return -1;    //无解
    if(row < var) return var - row;//row表示有用的方程数方程,但是要在判断出有解的前提下才能说有多组解;
    rep_1(i,var - 1,0){  // ***若为唯一解,其实就是var维方阵
        ll ret = a[i][var];
        for(j = i+1;j < var;j++) //利用已求得的变元消去第row行col后面的元素,得到一元方程;
            ret -= x[j]*a[i][j];
        ret = ((ret%MOD)+MOD)%MOD;
        int d,x1,y;
        //构造出 a[i][i]*x[i] + MOD*y = ret(mod MOD);且gcd(a[row][col],7) = 1)因为a[row][col] != 0
        if(a[i][i] < 0) a[i][i] = -a[i][i],ret = -ret;
        exgcd(a[i][i],MOD,d,x1,y); //之后乘上ret弄到3~9范围即可;
        x[i] = ((ret*(x1%MOD))%MOD+MOD)%MOD;
    }
    return 0;
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("data2.txt","w",stdout);
    int i,j,T,kase = 1;
    cin>>T;
    while(T--){
        MS0(x);MS0(a);
        char s[80];
        scanf("%d%s",&MOD,s);
        var = equ = strlen(s);
        rep0(i,0,var){
            if(s[i] == '*') a[i][var] = 0;
            else a[i][var] = s[i] - 'a' + 1;
        }
        rep0(i,0,var){
            a[i][0] = 1;
            rep0(j,1,var)
                a[i][j] = a[i][j-1]*(i+1)%MOD;
        }
        //debug();
        Gauss();
        rep0(i,0,var)
            printf("%I64d%c",x[i],i == var - 1?'
':' ');
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/hxer/p/5182385.html