poj 2065 SETI
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了poj 2065 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?‘\\n‘:‘ ‘); } return 0; }
以上是关于poj 2065 SETI的主要内容,如果未能解决你的问题,请参考以下文章