POJ2065 SETI(高斯消元 同模方程)

(a1 * 1^0  +   a2 * 1^1  + ...  an * 1^n - 1) % P = f1

....

(a1 * n^0  +   a2 * n^1  + ...  an - 1 * n ^ n - 1) % P = fn

消元中A[k][i] % A[i][i]不为0时将A[k][i]变为他们的最小公倍数,即整行都乘上lcm(A[k][i], A[i][i]) / A[k][i](不过后来看题解发现有更巧妙的方法不用求lcm),回代求解时使用逆元

 

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
#include<utility>
using namespace std;
typedef long long LL;
const int N = 100, INF = 0x3F3F3F3F;

int hs[256];
int inv[50000];
int p;
LL a[N][N];

template<typename T>
T gcd(T a, T b){
	while(b){
		T t = a % b;
		a = b;
		b = t;
	}
	return a;
}
template<typename T>
T lcm(T a, T b){
	return a / gcd(a, b) * b;
}

template<typename T>
void gauss_jordan(T A[N][N], int n){
    for(int i = 0; i < n; i++){
        //选择一行r与第i行交换
        int r = i;
        for(int j = i; j < n; j++){
            if(A[j][i]){
            	r = j;
            	break;
            }
        }
        if(A[r][i] == 0){
            continue;
        }

        if(r != i){
            for(int j = 0; j <= n; j++){
                swap(A[r][j], A[i][j]);
            }
        }
        for(int k = i + 1; k < n; k++){
            if(A[k][i]){
                if(A[k][i] % A[i][i]){
                    T d = lcm(A[k][i], A[i][i]) / A[k][i];
                    for(int j = i; j <= n; j++){
                        A[k][j] *= d;
                    }
                }
                T d = A[k][i] / A[i][i] % p;
                for(int j = n; j >= i; j--){
                    A[k][j] -=  d * A[i][j] % p;
                    A[k][j] = (A[k][j] % p + p) % p;
                }
            }
        }
    }
    for(int i = n - 1; i >= 0; i--){
    	for(int j = i + 1; j < n; j++){
    		A[i][n] -= A[j][n] * A[i][j] % p;
            A[i][n] = (A[i][n] % p + p) % p;
    	}
    	A[i][n] = A[i][n] * inv[A[i][i] % p] % p;
    }
}

char str[N];
int main(){
    memset(hs, 0, sizeof(hs));
    hs['*'] = 0;
    for(int i = 0; i < 26; i++){
    	hs[i + 'a'] = i + 1;
    }
    int t;
    cin>>t;
    while(t--){
    	int n;
    	cin>>p;
    	cin>>str;
    	inv[1] = 1;
    	for(int i = 2; i < p; i++){
    		inv[i] = (p - p / i ) * inv[p % i] % p;
    	}
    	n = strlen(str);
    	memset(a, 0, sizeof(a));
    	for(int i = 0; i < n; i++){
    		a[i][n] = hs[str[i]];
    		a[i][0] = 1;
    		for(int j = 1; j < n; j++){
    			a[i][j] = a[i][j - 1] * (i + 1) % p;
    		}
    	}
    	gauss_jordan(a, n);
    	cout<<a[0][n];
    	for(int i = 1; i < n; i++){
            cout<<' '<<a[i][n];
    	}
    	cout<<endl;
    }

    return 0;
}

  

转载于:https://www.cnblogs.com/IMGavin/p/5933037.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值