文章标题 POJ 2065 :SETI (高斯消元)

题目链接
题意:给你一个素数P(P<=30000)和一串长为n的字符串str[]。字母’*’代表0,字母a-z分别代表1-26,这n个字符所代表的数字分别代表f(1)、f(2)….f(n)。
定义f(k) = ∑(0<=i<=n-1)ai*k^i(mod p)
通过定义可以列出n个方程
f(1) = a0 * 1^0 + a1 * 1^1 + a2 * 1^2 ,,,,,,,a(n-1) * 1^n
f(2) = a0 * 1^0 + a1 * 2^1 + a2 * 2^2 ,,,,,,,a(n-1) * 2^n
f(3) = a0 * 3^0 + a1 * 3^1 + a2 * 3^2 ,,,,,,,a(n-1) * 3^n
,,,
,,,
f(n) = a0 * n^0 + a1 * n^1 + a2 * n^2 ,,,,,,,a(n-1) * n^n
然后用高斯消元求解就行了,题目已说明有唯一解
代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
#include <math.h>
#include <vector>
using namespace std;
typedef long long ll;

const int mod=1e9+7;
const int maxn=105;

ll mat[maxn][maxn];
ll p;
char str[105];
ll x[maxn];
bool free_x[maxn] ;

int guass(int n,int m){//n行m列 
    memset (x,0,sizeof (x));//把解集清空,所有变量都标为自由变量?
    memset (free_x,true,sizeof (free_x));
    int k,col;
    for (k=0,col=0;k<n&&col<m;k++,col++){//枚举行列
        int max_r=k;//找到该col列元素绝对值最大的那行与第k行交换.(为了在除法时减小误差)
        for (int i=k+1;i<n;i++){
            if (fabs(mat[i][col])>fabs(mat[max_r][col]))max_r=i;
        }
        if (max_r!=k){//变换 
            for (int i=k;i<m+1;i++)swap(mat[k][i],mat[max_r][i]);
        }
        for (int i=k+1;i<n;i++)if (mat[i][col]!=0){
            ll x1=mat[i][col],x2=mat[k][col];
            for (int j=col;j<m+1;j++){
                mat[i][j]=mat[i][j]*x2-x1*mat[k][j];
                mat[i][j]=(mat[i][j]%p+p)%p;
            }
        }
    }
    for (int i=k-1;i>=0;i--){
        ll tmp=mat[i][m];
        for (int j=i+1;j<m;j++){
            tmp=((tmp-mat[i][j]*x[j])%p+p)%p;
        }
        while (tmp%mat[i][i])tmp+=p;
        x[i]=((tmp/mat[i][i])%p+p)%p;
    }
    return 0;
}
int n;
int main()
{
    int T;
    scanf ("%d",&T);
    while (T--){
        scanf ("%lld",&p);
        scanf ("%s",str);
        memset (mat,0,sizeof (mat));
        int len=strlen(str); 
        for (int i=0;i<len;i++){
            if (str[i]!='*')mat[i][len]=str[i]-'a'+1;
            mat[i][0]=1;
            for (int j=1;j<len;j++){
                mat[i][j]=(mat[i][j-1]*(i+1))%p;    
            }
        }   
        guass(len,len);
        for(int i=0;i<len;i++){
            if (!i)printf ("%d",x[i]);
            else printf (" %d",x[i]);
        } 
        printf ("\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值