数论训练-高斯消元

数论训练-高斯消元

POJ 2065 SETI

Description

For some years, quite a lot of work has been put into listening to electromagnetic radio signals received from space, in order to understand what civilizations in distant galaxies might be trying to tell us. One signal source that has been of particular interest to the scientists at Universit´e de Technologie Spatiale is the Nebula Stupidicus.
Recently, it was discovered that if each message is assumed to be transmitted as a sequence of integers 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, provided that the correct value of p is used. n is of course the length of the transmitted message, and the ai denote integers such that 0 <= ai < p. p is a prime number that is guaranteed to be larger than n as well as larger than 26. It is, however, known to never exceed 30 000.
These relationships altogether have been considered too peculiar for being pure coincidences, which calls for further investigation.
The linguists at the faculty of Langues et Cultures Extraterrestres transcribe these messages to strings in the English alphabet to make the messages easier to handle while trying to interpret their meanings. The transcription procedure simply assigns the letters a…z to the values 1…26 that f (k) might evaluate to, such that 1 = a, 2 = b etc. The value 0 is transcribed to ‘*’ (an asterisk). While transcribing messages, the linguists simply loop from k = 1 to n, and append the character corresponding to the value of f (k) at the end of the string.
The backward transcription procedure, has however, turned out to be too complex for the linguists to handle by themselves. You are therefore assigned the task of writing a program that converts a set of strings to their corresponding Extra Terrestial number sequences.

Input

On the first line of the input there is a single positive integer N, telling the number of test cases to follow. Each case consists of one line containing the value of p to use during the transcription of the string, followed by the actual string to be transcribed. The only allowed characters in the string are the lower case letters ‘a’…‘z’ and ‘*’ (asterisk). No string will be longer than 70 characters.

Output

For each transcribed string, output a line with the corresponding list of integers, separated by space, with each integer given in the order of ascending values of i.

Sample Input

3
31 aaa
37 abc
29 hello*earth

Sample Output

1 0 0
0 1 0
8 13 9 13 4 27 18 10 12 24 15

-------------------------------------------------------------分割线--------------------------------------------------------------

题意

给定一个模数p
第i个方程为a1*(i ^ 0)+a2*(i ^ 1)+…an*(i ^ (n-1)) mod p == num[i] mod p
num[i]为输入的字符串的第i位,a~z分别对应1 ~ 26,*对应0

坑点

不能忘了取模,并且在计算i ^ n的时候也要边乘边取模,不然会炸LL
------------------------------------------------------------分割线---------------------------------------------------------------

代码

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstdlib>
#include <cstring>

using namespace std;

int MOD = 7;
const int MAXN = 400;
int a[MAXN][MAXN];//增广矩阵
int x[MAXN];//最后得到的解集

inline int gcd(int a,int b)
{
    while(b != 0)
    {
        int t = b;
        b = a%b;
        a = t;
    }
    return a;
}

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

long long inv(long long a,long long m)
{
    if(a == 1)
        return 1;
    return inv(m%a,m)*(m-m/a)%m;
}

int Gauss(int equ,int var)
{
    int max_r,col,k;
    for(k = 0, col = 0; k < equ && col < var; k++,col++)
    {
        max_r = k;
        for(int i = k+1; i < equ; i++)
            if(abs(a[i][col]) > abs(a[max_r][col]))
                max_r = i;
        if(a[max_r][col] == 0)
        {
            k--;
            continue;
        }
        if(max_r != k)
            for(int j = col; j < var+1; j++)
                swap(a[k][j],a[max_r][j]);
        for(int i = k+1; i < equ; i++)
        {
            if(a[i][col] != 0)
            {
                int LCM = lcm(abs(a[i][col]),abs(a[k][col]));
                int ta = LCM/abs(a[i][col]);
                int tb = LCM/abs(a[k][col]);
                if(a[i][col]*a[k][col] < 0)
                    tb = -tb;
                for(int j = col; j < var+1; j++)
                    a[i][j] = ((a[i][j]*ta - a[k][j]*tb)%MOD + MOD)%MOD;
            }
        }
    }
    for(int i = k; i < equ; i++)
        if(a[i][col] != 0)
            return -1;//无解
    if(k < var)
        return var-k;//多解
    for(int i = var-1; i >= 0; i--)
    {
        int temp = a[i][var];
        for(int j = i+1; j < var; j++)
        {
            if(a[i][j] != 0)
            {
                temp -= a[i][j]*x[j];
                temp = (temp%MOD + MOD)%MOD;
            }
        }
        x[i] = (temp*inv(a[i][i],MOD))%MOD;
    }
    return 0;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(a,0,sizeof(a));
        int p;
        scanf("%d",&p);
        MOD=p;
        char str[75];
        scanf("%s",str);
        int n=strlen(str);
        for(int i=0;i<n;i++)
        {
            int cnt=1;
            for(int j=0;j<n;j++)
            {
                a[i][j]=cnt;
                cnt=(cnt*(i+1))%MOD;
            }
            if(str[i]=='*')
            {
                a[i][n]=0;
            }
            else
            {
                a[i][n]=str[i]-'a'+1;
            }
        }
        Gauss(n,n);
        for(int i=0;i<n;i++)
        {
            i==0||printf(" ");
            printf("%d",x[i]);
        }
        printf("\n");
    }
    return 0;
}

------------------------------------------------------分割线---------------------------------------------------------------------

POJ 2947 Widget Factory

Description

The widget factory produces several different kinds of widgets. Each widget is carefully built by a skilled widgeteer. The time required to build a widget depends on its type: the simple widgets need only 3 days, but the most complex ones may need as many as 9 days.
The factory is currently in a state of complete chaos: recently, the factory has been bought by a new owner, and the new director has fired almost everyone. The new staff know almost nothing about building widgets, and it seems that no one remembers how many days are required to build each diofferent type of widget. This is very embarrassing when a client orders widgets and the factory cannot tell the client how many days are needed to produce the required goods. Fortunately, there are records that say for each widgeteer the date when he started working at the factory, the date when he was fired and what types of widgets he built. The problem is that the record does not say the exact date of starting and leaving the job, only the day of the week. Nevertheless, even this information might be helpful in certain cases: for example, if a widgeteer started working on a Tuesday, built a Type 41 widget, and was fired on a Friday,then we know that it takes 4 days to build a Type 41 widget. Your task is to figure out from these records (if possible) the number of days that are required to build the different types of widgets.

Input

The input contains several blocks of test cases. Each case begins with a line containing two integers: the number 1 ≤ n ≤ 300 of the different types, and the number 1 ≤ m ≤ 300 of the records. This line is followed by a description of the m records. Each record is described by two lines. The first line contains the total number 1 ≤ k ≤ 10000 of widgets built by this widgeteer, followed by the day of week when he/she started working and the day of the week he/she was fired. The days of the week are given bythe strings MON',TUE’, WED',THU’, FRI',SAT’ and `SUN’. The second line contains k integers separated by spaces. These numbers are between 1 and n , and they describe the diofferent types of widgets that the widgeteer built. For example, the following two lines mean that the widgeteer started working on a Wednesday, built a Type 13 widget, a Type 18 widget, a Type 1 widget, again a Type 13 widget,and was fired on a Sunday.
4 WED SUN
13 18 1 13
Note that the widgeteers work 7 days a week, and they were working on every day between their first and last day at the factory (if you like weekends and holidays, then do not become a widgeteer!).
The input is terminated by a test case with n = m = 0 .

Output

For each test case, you have to output a single line containing n integers separated by spaces: the number of days required to build the different types of widgets. There should be no space before the first number or after the last number, and there should be exactly one space between two numbers. If there is more than one possible solution for the problem, then write ‘Multiple solutions.’ (without the quotes). If you are sure that there is no solution consistent with the input, then write `Inconsistent data.’(without the quotes).

Sample Input

2 3
2 MON THU
1 2
3 MON FRI
1 1 2
3 MON SUN
1 2 2
10 2
1 MON TUE
3
1 MON WED
3
0 0

Sample Output

8 3
Inconsistent data.

Hint

Huge input file, ‘scanf’ recommended to avoid TLE.

-----------------------------------------分割线----------------------------------------------------------------------------------

题意

有n种零件,已知每种零件的加工时间最少为3天最多为9天,现在只知道有m个工程用的时间和加工的每种零件的数量,求每种零件所需的加工时间。

思路

带模数的高斯消元

坑点

几乎所有的数都需要一直MOD,包括增广矩阵。增广矩阵没有模RE到自闭的卑微小黄如是说到。
在这里插入图片描述
------------------------------------分割线---------------------------------------------------------------------------------------

代码

(模板来源于邝斌大神)

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>

using namespace std;

typedef long long ll;

const int MOD = 7;
const int MAXN = 405;
int a[MAXN][MAXN];//增广矩阵
ll x[MAXN];//最后得到的解集

inline int gcd(int a,int b)
{
    while(b != 0)
    {
        int t = b;
        b = a%b;
        a = t;
    }
    return a;
}

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

long long inv(long long a,long long m)
{
    if(a == 1)
        return 1;
    return inv(m%a,m)*(m-m/a)%m;
}

int Gauss(int equ,int var)
{
    int max_r,col,k;
    for(k = 0, col = 0; k < equ && col < var; k++,col++)
    {
        max_r = k;
        for(int i = k+1; i < equ; i++)
            if(abs(a[i][col]) > abs(a[max_r][col]))
                max_r = i;
        if(a[max_r][col] == 0)
        {
            k--;
            continue;
        }
        if(max_r != k)
            for(int j = col; j < var+1; j++)
                swap(a[k][j],a[max_r][j]);
        for(int i = k+1; i < equ; i++)
        {
            if(a[i][col] != 0)
            {
                int LCM = lcm(abs(a[i][col]),abs(a[k][col]));
                int ta = LCM/abs(a[i][col]);
                int tb = LCM/abs(a[k][col]);
                if(a[i][col]*a[k][col] < 0)
                    tb = -tb;
                for(int j = col; j < var+1; j++)
                    a[i][j] = ((a[i][j]*ta - a[k][j]*tb)%MOD + MOD)%MOD;
            }
        }
    }
    for(int i = k; i < equ; i++)
        if(a[i][col] != 0)
            return -1;//无解
    if(k < var)
        return var-k;//多解
    for(int i = var-1; i >= 0; i--)
    {
        int temp = a[i][var];
        for(int j = i+1; j < var; j++)
        {
            if(a[i][j] != 0)
            {
                temp -= a[i][j]*x[j];
                temp = (temp%MOD + MOD)%MOD;
            }
        }
        x[i] = (temp*inv(a[i][i],MOD))%MOD;
    }
    return 0;
}

int fun(char str[])
{
    if(str[0]=='M'&&str[1]=='O'&&str[2]=='N')
        return 1;
    else if(str[0]=='T'&&str[1]=='U'&&str[2]=='E')
        return 2;
    else if(str[0]=='W'&&str[1]=='E'&&str[2]=='D')
        return 3;
    else if(str[0]=='T'&&str[1]=='H'&&str[2]=='U')
        return 4;
    else if(str[0]=='F'&&str[1]=='R'&&str[2]=='I')
        return 5;
    else if(str[0]=='S'&&str[1]=='A'&&str[2]=='T')
        return 6;
    else if(str[0]=='S'&&str[1]=='U'&&str[2]=='N')
        return 7;
    return -1;
}

ll num[10005];

int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        if(n==0&&m==0)
            break;
        for(int i=0;i<m;i++)
        {
            memset(num,0,sizeof(num));
            int k;
            char s[10],e[10];
            scanf("%d%s%s",&k,s,e);
            for(int j=0;j<k;j++)
            {
                int x;
                scanf("%d",&x);
                num[x]++;
            }
            for(int j=1;j<=n;j++)
            {
                a[i][j-1]=num[j]%7;
            }
            a[i][n]=((fun(e)-fun(s)+8)%7+7)%7;
        }
        int ans=Gauss(m,n);
        if(ans==-1)
            printf("Inconsistent data.\n");
        else if(ans>0)
        {
            printf("Multiple solutions.\n");
        }
        else
        {
            for(int i=0;i<n;i++)
            {
                i==0||printf(" ");
                if(x[i]>=3&&x[i]<=9)
                {
                    printf("%lld",x[i]);
                }
                else
                {
                    printf("%lld",x[i]%7+7);
                }
            }
            printf("\n");
        }
    }
    return 0;
}

---------------------------------------------------------分割线------------------------------------------------------------------

发布了42 篇原创文章 · 获赞 6 · 访问量 4032

猜你喜欢

转载自blog.csdn.net/qq_43383246/article/details/97627028
今日推荐