高斯消元总结

什么是高斯消元

高斯消元是用于解形如\left\{\begin{matrix}a_{11}x_{1}+a_{12}x_{2}+...+a_{1n}x_{n} = b_{1} \\ a_{21}x_{1}+a_{22}x_{2}+...+a_{2n}x_{n} = b_{2} \\ ....... \\ a_{m1}x_{1}+a_{m2}x_{2}+...+a_{mn}x_{n} = b_{m} \end{matrix}\right.的线性方程组的。

我们可以将系数存在系数和常数保存在增广矩阵中,通过行变换列变换求解。

 高斯消元的思想是,将方程组中一方程中的未知数用含有另一未知数的方程表示,代入原方程,即可消去原方程的一个未知数。可以看出,高斯消元的时间复杂度是O(n^3)的。

我们来看一个例子:

求解线性方程组

首先,要将L1以下的等式中的x消除,然后再将L2以下的等式中的y消除。这样可使整个方程组变成一个三角形似的格式。之后再将已得出的答案一个个地代入已被简化的等式中的未知数中,就可求出其余的答案了。

 

 

高斯消元的代码实现

这是一个解多元模线性方程组的实现方法

int a[maxn][maxn];
int x[maxn];
bool free_x[maxn];
int n;
int mod;
int gcd(int x, int y)
{
    if(y == 0)
        return x;
    return gcd(y,x%y);
}
int lcm(int x, int y)
{
    return x/gcd(x,y)*y;
}
int Gauss()
{
    int i,j;
    int row,col,max_r;// 当前这列绝对值最大的行;
    int LCM;
    int ta,tb;
    int tmp;
    for(row=0,col=0; row<n&&col<n; row++,col++)
    {
        // 枚举当前处理的行.
        // 找到该col列元素绝对值最大的那行与第row行交换.(为了在除法时减小误差)
        max_r=row;
        for(i=row+1; i<n; i++)
        {
            if(abs(a[i][col])>abs(a[max_r][col]))
                max_r=i;
        }
        if(max_r!=row)
        {
            // 与第row行交换
            for(j=row; j<n+1; j++)
                swap(a[row][j],a[max_r][j]);
        }
        if(a[row][col]==0)
        {
            // 说明该col列第row行以下全是0了,则处理当前行的下一列.
            row--;
            continue;
        }
        for(i=row+1; i<n; i++)
        {
            // 枚举要删去的行.
            if(a[i][col]!=0)
            {
                LCM=lcm(abs(a[i][col]),abs(a[row][col]));
                ta=LCM/abs(a[i][col]);
                tb=LCM/abs(a[row][col]);
                if(a[i][col]*a[row][col]<0) tb=-tb;//异号的情况是相加
                for(j=col; j<n+1; j++)
                {
                    a[i][j]=(((a[i][j]*ta-a[row][j]*tb)%mod+mod)%mod);
                }
            }
        }
    }
    // 1. 无解的情况: 化简的增广阵中存在(0, 0, ..., a)这样的行(a != 0).
    for(i=row; i<n; i++)
    {
        if(a[i][col]!=0)  return -1;
    }
    // 2. 无穷解的情况: 在n * (n + 1)的增广阵中出现(0, 0, ..., 0)这样的行,即说明没有形成严格的上三角阵.
    // 且出现的行数即为自由变元的个数.
    if(row<n)
    {
        int free_index;
        int free_x_num;
        //自由变元有n-row个,即不确定的变元至少有var-k个.
        for(i = row-1; i>=0; i--)
        {
            // 用于判断该行中的不确定的变元的个数,如果超过1个,则无法求解,它们仍然为不确定的变元.
            free_x_num = 0;
            for(j = 0; j<n; j++)
            {
                if(a[i][j] && free_x[j])
                {
                    free_x_num++;
                    free_index = j;
                }
            }
            if(free_x_num>1)
                continue;
            tmp = a[i][n];
            for(j = 0; j<n; j++)
            {
                if(a[i][j] && free_index != j)
                    tmp -= a[i][j]*x[j]%mod;
                tmp = (tmp%mod+mod)%mod;
            }
            x[free_index] = tmp/a[i][free_index];
            free_x[free_index] = 0;

        }

        return n-row;
    }
     // 3. 唯一解的情况: 在n * (n + 1)的增广阵中形成严格的上三角阵.
    // 计算出Xn-1, Xn-2 ... X0.
    for(i=n-1; i>=0; i--)
    {
        tmp=a[i][n];//等式右边的数
        for(j=i+1; j<n; j++)
        {
            if(a[i][j]!=0) tmp-=a[i][j]*x[j];//把已知的解带入,减去,只剩下,一个未知的解
            tmp=(tmp%mod+mod)%mod;
        }
        while(tmp%a[i][i]!=0)//外层每次循环都是为了求 a[i][i],因为它是每个方程中唯一一个未知的变量(求该方程时)
            tmp+=mod;//因为不确定,而aug[i][i]必须得为整数才可以,周期为mod
        x[i]=(tmp/a[i][i])%mod;
    }
    return 0;
}

典型例题

1.POJ-1222(高斯消元求解异或方程组)

In an extended version of the game Lights Out, is a puzzle with 5 rows of 6 buttons each (the actual puzzle has 5 rows of 5 buttons each). Each button has a light. When a button is pressed, that button and each of its (up to four) neighbors above, below, right and left, has the state of its light reversed. (If on, the light is turned off; if off, the light is turned on.) Buttons in the corners change the state of 3 buttons; buttons on an edge change the state of 4 buttons and other buttons change the state of 5. For example, if the buttons marked X on the left below were to be pressed,the display would change to the image on the right.


The aim of the game is, starting from any initial set of lights on in the display, to press buttons to get the display to a state where all lights are off. When adjacent buttons are pressed, the action of one button can undo the effect of another. For instance, in the display below, pressing buttons marked X in the left display results in the right display.Note that the buttons in row 2 column 3 and row 2 column 5 both change the state of the button in row 2 column 4,so that, in the end, its state is unchanged.


Note:
1. It does not matter what order the buttons are pressed.
2. If a button is pressed a second time, it exactly cancels the effect of the first press, so no button ever need be pressed more than once.
3. As illustrated in the second diagram, all the lights in the first row may be turned off, by pressing the corresponding buttons in the second row. By repeating this process in each row, all the lights in the first
four rows may be turned out. Similarly, by pressing buttons in columns 2, 3 ?, all lights in the first 5 columns may be turned off.
Write a program to solve the puzzle.

Input

The first line of the input is a positive integer n which is the number of puzzles that follow. Each puzzle will be five lines, each of which has six 0 or 1 separated by one or more spaces. A 0 indicates that the light is off, while a 1 indicates that the light is on initially.

Output

For each puzzle, the output consists of a line with the string: "PUZZLE #m", where m is the index of the puzzle in the input file. Following that line, is a puzzle-like display (in the same format as the input) . In this case, 1's indicate buttons that must be pressed to solve the puzzle, while 0 indicate buttons, which are not pressed. There should be exactly one space between each 0 or 1 in the output puzzle-like display.

Sample Input

2
0 1 1 0 1 0
1 0 0 1 1 1
0 0 1 0 0 1
1 0 0 1 0 1
0 1 1 1 0 0
0 0 1 0 1 0
1 0 1 0 1 1
0 0 1 0 1 1
1 0 1 1 0 0
0 1 0 1 0 0

Sample Output

PUZZLE #1
1 0 1 0 0 1
1 1 0 1 0 1
0 0 1 0 1 1
1 0 0 1 0 0
0 1 0 0 0 0
PUZZLE #2
1 0 0 1 1 1
1 1 0 0 0 0
0 0 0 1 0 0
1 1 0 1 0 1
1 0 1 1 0 1

思路:

题意是给定哪些灯开关有关系,即这些有关系的开关要按一个其他的也跟着按,问要怎么按可以将灯全部关掉。

由于开关是0,1两个状态,那么我们就可以将此类问题当作异或结果为0的问题来考虑。

假设当前此开关状态为x5(1代表按下,0代表未按下),则只要保证该开关上下左右的开关x1,x2,x3,x4与该开关异或结果为0即可,即得方程x1^x2^x3^x4^x5 = 0。对于每个开关的初态,都可以建立一个方程,则得线性方程组。

原本的高斯消元求解中,找绝对值最大改成找1,消元的加号改成^异或就可以。

 代码:

#include <cstdio>
#include <stack>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#include <map>
#include <vector>
#include <queue>
#include <set>
#define eps 1e-8
typedef long long ll;
const double PI = acos(-1.0);
const int maxn = 1e6;
const int INF = 0x3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;
using namespace std;
int equ,var;
int a[32][32];
int x[32];
void Gauss()
{
	int k,max_r,col;
	for(k=0,col=0; k<equ&&col<var; ++k,++col)
	{
		max_r=k;
		//列主元法
        //找第col个自由元系数绝对值最大的行i(i > k) 与 当前行(k行)交换
		for(int i=k+1;i<equ;++i)
		{
			if(a[i][col]>a[max_r][col])
				max_r=i;
		}
		//找到——交换
		if(max_r!=k)
		{
			for(int i=col;i<=var;++i)
				swap(a[k][i],a[max_r][i]);
		}
		// 说明该col列第k行以下全是0了,则处理当前行的下一列.
		if(a[k][col]==0)
		{
			k--;
			continue;
		}
		//枚举要删去的行
		for(int i=k+1;i<=equ;++i)
		{
			if(a[i][col]!=0)
			{
				for(int j=col;j<=var;++j)
					a[i][j]^=a[k][j];
			}
		}
	}
	//得到三角矩阵,回代求解
	for(int i=var-1; i>=0; --i)
	{
		x[i]=a[i][var];
		for(int j=i+1;j<var;++j)
			x[i]^=(a[i][j]*x[j]);
	}
}
int main()
{
    //ios::sync_with_stdio(false);
    int T;
    scanf("%d",&T);
    int tt = 1;
    while(T--)
    {
        memset(a,0,sizeof a);
        equ = 30, var = 30;
        for(int i = 0; i<5; i++)
        {
            for(int j = 0; j<6; j++)
            {
                a[i*6+j][i*6+j] = 1;
                if(i>0)
                    a[i*6+j][(i-1)*6+j] = 1;
                if(j)
                    a[i*6+j][i*6+j-1] = 1;
                if(i<4)
                    a[i*6+j][(i+1)*6+j] = 1;
                if(j<5)
                    a[i*6+j][i*6+j+1] = 1;
            }
        }
        for(int i = 0; i<30; i++)
            scanf("%d",&a[i][30]);
        Gauss();
        printf("PUZZLE #%d\n",tt++);
        for(int i = 0; i<30; i++)
        {
            if((i+1)%6)
                cout<<x[i]<<" ";
            else
                cout<<x[i]<<endl;
        }
    }

    return 0;
}

 2.洛谷P4783(高斯消元矩阵求逆)

题目描述

求一个 N×N的矩阵的逆矩阵。答案对10^9+7109+7取模。

输入格式

第一行有一个整数N,代表矩阵的大小;

从第2行到第N+1行,每行N个整数,其中第i+1行第j列的数代表矩阵中的元素aij​。

输出格式

若矩阵可逆,则输出N行,每行N个整数,其中第ii行第jj列的数代表逆矩阵中的元素bij​,答案对10^9+7取模;

否则只输出一行 No Solution

输入输出样例

输入 #1复制

3
1 2 8
2 5 6
5 1 2

输出 #1复制

718750005 718750005 968750007
171875001 671875005 296875002
117187501 867187506 429687503

输入 #2复制

3
3 2 4
7 2 9
2 4 3

输出 #2复制

No Solution

说明/提示

对30%的数据有N≤100;

对100%的数据有N≤400,所有aij<10^9+7。

ps.TLE的同学可以试试大力卡常,标算不开O2勉强能卡过去的

 思路:矩阵求逆,即在系数矩阵之后添加一个单位阵,行变换后左边N*N矩阵化为单位阵,右边单位阵就是该矩阵的逆矩阵。 

代码:

/**
    高斯消元矩阵求逆
**/
#include <cstdio>
#include <stack>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#include <map>
#include <vector>
#include <queue>
#include <set>
#define eps 1e-8
typedef long long ll;
const double PI = acos(-1.0);
const int maxn = 1005;
const int INF = 0x3f3f3f;
const ll mod = 1e9+7;
const ll linf = 0x3f3f3f3f3f3f3f3f;
using namespace std;
int n,m;
ll f[maxn][maxn];
ll r,ret;
ll ksm(ll a, ll b)//求逆元
{
    ret = 1;
    while(b)
    {
        if(b&1)
            ret = ret*a%mod;
        a = a*a%mod;
        b >>= 1;
    }
    return ret;
}
int main()
{
    scanf("%d",&n);
    m = n*2;
    for(int i = 1; i<=n; i++)
    {
        for(int j = 1; j<=n; j++)
        {
            scanf("%lld",&f[i][j]);
        }
        f[i][n+i] = 1;
    }
    //高斯消元模板
    for(int i = 1; i<=n; i++)
    {
        for(int j = i; j<=n; j++)
        {
            //找到xi的系数不为0的一个方程
            if(f[j][i])
            {
                for(int k = 1; k<=m; k++)
                    swap(f[i][k],f[j][k]);
                break;
            }
        }
        if(!f[i][i])
        {
            cout<<"No Solution"<<endl;
            return 0;
        }
        r = ksm(f[i][i],mod-2);
        //将该方程的xi的系数变为1
        for(int j = i; j<=m; j++)
            f[i][j] = f[i][j]*r%mod;
        //消去其他方程的xi的系数
        for(int j = 1; j<=n; j++)
        {
            if(j != i)
            {
                for(int k = i; k<=m; k++)
                    f[j][k] = (f[j][k] - f[j][i]*f[i][k]%mod + mod)%mod;
            }
        }
    }
        for(int i = 1; i<=n; i++)
        {
            for(int j = n+1; j<=m; j++)
                cout<<f[i][j]<<" ";
            cout<<endl;
        }
 
    return 0;
}

3.洛谷P1092(高斯消元+搜索)

题目描述
所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母。来看一个简单的例子:

 43#9865#045
+  8468#6633
 44445509678
其中#号代表被虫子啃掉的数字。根据算式,我们很容易判断:第一行的两个数字分别是5和3,第二行的数字是5。

现在,我们对问题做两个限制:

首先,我们只考虑加法的虫食算。这里的加法是NN进制加法,算式中三个数都有N位,允许有前导的0。

其次,虫子把所有的数都啃光了,我们只知道哪些数字是相同的,我们将相同的数字用相同的字母表示,不同的数字用不同的字母表示。如果这个算式是N进制的,我们就取英文字母表午的前N个大写字母来表示这个算式中的0到N−1这N个不同的数字:但是这N个字母并不一定顺序地代表0到N−1。输入数据保证N个字母分别至少出现一次。

 BADC
+CBDA
 DCCC
上面的算式是一个4进制的算式。很显然,我们只要让ABCD分别代表0123,便可以让这个式子成立了。你的任务是,对于给定的N进制加法算式,求出N个不同的字母分别代表的数字,使得该加法算式成立。输入数据保证有且仅有一组解。

输入格式
包含四行。
第一行有一个正整数N(N≤26)。

后面的三行,每行有一个由大写字母组成的字符串,分别代表两个加数以及和。这3个字符串左右两端都没有空格,从高位到低位,并且恰好有N位。

输出格式
一行,即唯一的那组解。

解是这样表示的:输出N个数字,分别表示A,B,C,…所代表的数字,相邻的两个数字用一个空格隔开,不能有多余的空格。

输入输出样例
输入 #1复制

5
ABCED
BDACE
EBBAA
输出 #1复制

1 0 3 4 2
说明/提示
对于30%的数据,保证有N≤10;

对于50%的数据,保证有N≤15;

对于全部的数据,保证有N≤26。

noip2004提高组第4题
 

思路:

首先,假设我们有n进制的加法算式a + b = c

对于第i位的加法运算,考虑上一位的加法的进位di-1和本位加法进位,有ai + bi = ci + di-1 + n*di

即,每一位的进位di只能取1或0,当然,d0只能为0,本题中dn也只能为0。

将ci移至等式的右边,得

至此,如果我们将A,B,C,.....,Z分别记为x1,x2,x3,……,x26,那么我们便可列出方程,利用高斯消元求解增广矩阵了。

由于di只能为0或1,所以我们可以对di进行枚举,但是,高斯消元的复杂度是n3的,搜索或枚举+高斯消元,这种方法的复杂度爆了,是2^n * n3,所以,我们可以先将得到的增广矩阵左边利用高斯消元,求解出,然后再对di进行枚举,判断解的合法性,这样的复杂度是n^3 + 2^n*n^2的。

代码:

二进制状压:

#include <cstdio>
#include <stack>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#include <map>
#include <vector>
#include <queue>
#include <set>
#define eps 1e-8
typedef long long ll;
const double PI = acos(-1.0);
const int maxn = 1005;
const int INF = 0x3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;
using namespace std;
int a[maxn][maxn],g[maxn][maxn];
int d[maxn],x[maxn];
int vis[maxn];
int n;
string s[3];
int equ,var;
int gcd(int a, int b)
{
    return b == 0?a:gcd(b,a%b);
}
void gauss()
{
    int row,col,mxr,lcm;
    for(row = col = 1;row<=equ&& col<=var; row++,col++)
    {
        mxr = row;
        for(int i = row+1; i<=equ; i++)
        {
            if(abs(a[i][col])>abs(a[mxr][col]))
                mxr = i;
        }
        if(mxr != row)
        {
            swap(a[row],a[mxr]);
            swap(g[row],g[mxr]);
        }
        if(!a[row][col])
        {
            row--;
            continue;
        }
        for(int i = 1; i<=equ; i++)
        {
            if(i!=row && a[i][col])
            {
                lcm = a[i][col]/gcd(a[i][col],a[row][col])*a[row][col];
                int t1 = lcm/a[i][col];
                int t2 = lcm/a[row][col];
                for(int j = 1; j<=var; j++)
                {
                    g[i][j] = t1*g[i][j] - t2*g[row][j];
                    a[i][j] = t1*a[i][j] - t2*a[row][j];
                }
            }
        }
    }
}
int check()
{
    memset(vis,0,sizeof vis);
    for(int i = 1; i<=n; i++)
    {
        x[i] = 0;
        for(int j = 1; j<=n; j++)
            x[i] += g[i][j]*d[j];
        //判断最终解出的x[i]/a[i][i]是否合法
        //x[i]/a[i][i]应该为0~n-1的整数,且各不相同
        if(x[i]%a[i][i] ||  x[i]/a[i][i]<0)
            return 0;
        if(x[i]/a[i][i]>=n || vis[x[i]/a[i][i]])
            return 0;
        x[i] /= a[i][i];
        vis[x[i]] = 1;
    }
    return 1;
}
void solve()
{
    for(int i = 0; i<(1<<n); i++)
    {
        for(int j = 0; j<n; j++)
        {
            if(i&(1<<j))
                d[j+1] = 1;
            else
                d[j+1] = 0;
        }
        if(check())
        {
            for(int j = 1; j<=n; j++)
                cout<<x[j]<<" ";
            cout<<endl;
        }
    }
}
int main()
{
    cin>>n;
    for(int i = 0; i<3; i++)
        cin>>s[i];
    for(int  i = 0; i<n; i++)
    {
        for(int j = 0; j<2; j++)
            a[n-i][s[j][i]-'A'+1]++;
        a[n-i][s[2][i]-'A'+1]--;
    }
    for(int i = 1; i<=n; i++)
    {
        g[i][i] = n;
        g[i][i-1] = -1;
    }
    g[1][0] = 0;
    equ = var = n;
    gauss();
    solve();
    return 0;
}

 dfs:

#include <cstdio>
#include <stack>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#include <map>
#include <vector>
#include <queue>
#include <set>
#define eps 1e-8
typedef long long ll;
const double PI = acos(-1.0);
const int maxn = 1005;
const int INF = 0x3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;
using namespace std;
int a[maxn][maxn],g[maxn][maxn];
int d[maxn],x[maxn];
int vis[maxn];
int n;
string s[3];
int equ,var;
int gcd(int a, int b)
{
    return b == 0?a:gcd(b,a%b);
}
void gauss()
{
    int row,col,mxr,lcm;
    for(row = col = 1;row<=equ&& col<=var; row++,col++)
    {
        mxr = row;
        for(int i = row+1; i<=equ; i++)
        {
            if(abs(a[i][col])>abs(a[mxr][col]))
                mxr = i;
        }
        if(mxr != row)
        {
            swap(a[row],a[mxr]);
            swap(g[row],g[mxr]);
        }
        if(!a[row][col])
        {
            row--;
            continue;
        }
        for(int i = 1; i<=equ; i++)
        {
            if(i!=row && a[i][col])
            {
                lcm = a[i][col]/gcd(a[i][col],a[row][col])*a[row][col];
                int t1 = lcm/a[i][col];
                int t2 = lcm/a[row][col];
                for(int j = 1; j<=var; j++)
                {
                    g[i][j] = t1*g[i][j] - t2*g[row][j];
                    a[i][j] = t1*a[i][j] - t2*a[row][j];
                }
            }
        }
    }
}
int check()
{
    memset(vis,0,sizeof vis);
    for(int i = 1; i<=n; i++)
    {
        x[i] = 0;
        for(int j = 1; j<=n; j++)
            x[i] += g[i][j]*d[j];
        if(x[i]%a[i][i] ||  x[i]/a[i][i]<0)
            return 0;
        if(x[i]/a[i][i]>=n || vis[x[i]/a[i][i]])
            return 0;
        x[i] /= a[i][i];
        vis[x[i]] = 1;
    }
    return 1;
}
void dfs(int pos)
{
    if(pos == n)
    {
        if(check())
        {
            for(int i = 1; i<n; i++)
                cout<<x[i]<<" ";
            cout<<x[n]<<endl;
        }
        return;
    }
    d[pos] = 1;
    dfs(pos+1);
    d[pos] = 0;
    dfs(pos+1);
}
int main()
{
    cin>>n;
    for(int i = 0; i<3; i++)
        cin>>s[i];
    for(int  i = 0; i<n; i++)
    {
        for(int j = 0; j<2; j++)
            a[n-i][s[j][i]-'A'+1]++;
        a[n-i][s[2][i]-'A'+1]--;
    }
    for(int i = 1; i<=n; i++)
    {
        g[i][i] = n;
        g[i][i-1] = -1;
    }
    g[1][0] = 0;
    equ = var = n;
    gauss();
    dfs(1);
    return 0;
}

 4.POJ-1830(高斯消元求解异或方程组)

有N个相同的开关,每个开关都与某些开关有着联系,每当你打开或者关闭某个开关的时候,其他的与此开关相关联的开关也会相应地发生变化,即这些相联系的开关的状态如果原来为开就变为关,如果为关就变为开。你的目标是经过若干次开关操作后使得最后N个开关达到一个特定的状态。对于任意一个开关,最多只能进行一次开关操作。你的任务是,计算有多少种可以达到指定状态的方法。(不计开关操作的顺序)

Input

输入第一行有一个数K,表示以下有K组测试数据。
每组测试数据的格式如下:
第一行 一个数N(0 < N < 29)
第二行 N个0或者1的数,表示开始时N个开关状态。
第三行 N个0或者1的数,表示操作结束后N个开关的状态。
接下来 每行两个数I J,表示如果操作第 I 个开关,第J个开关的状态也会变化。每组数据以 0 0 结束。

Output

如果有可行方法,输出总数,否则输出“Oh,it's impossible~!!” 不包括引号

Sample Input

2
3
0 0 0
1 1 1
1 2
1 3
2 1
2 3
3 1
3 2
0 0
3
0 0 0
1 0 1
1 2
2 1
0 0

Sample Output

4
Oh,it's impossible~!!

Hint

第一组数据的说明:
一共以下四种方法:
操作开关1
操作开关2
操作开关3
操作开关1、2、3 (不记顺序)

思路:

与题1类似,只是这次直接告诉你哪几个开关相关,仍旧建立彼此相关的n*m个方程,求解方程,答案总数就是(2^自由元个数)

 代码:

#include <cstdio>
#include <stack>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#include <map>
#include <vector>
#include <queue>
#include <set>
#define eps 1e-8
typedef long long ll;
const double PI = acos(-1.0);
const int maxn = 1e6;
const int INF = 0x3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;
using namespace std;
int a[32][32];
int equ,var;
int from[32];
int to[32];
int Gauss()
{
    int k,max_r,col;
	for(k=0,col=0; k<equ&&col<var; ++k,++col)
	{
		max_r=k;
		//列主元法
        //找第col个自由元系数绝对值最大的行i(i > k) 与 当前行(k行)交换
		for(int i=k+1;i<equ;++i)
		{
			if(a[i][col]>a[max_r][col])
				max_r=i;
		}
		//找到——交换
		if(max_r!=k)
		{
			for(int i=col;i<=var;++i)
				swap(a[k][i],a[max_r][i]);
		}
		// 说明该col列第k行以下全是0了,则处理当前行的下一列.
		if(a[k][col]==0)
		{
			k--;
			continue;
		}
		//枚举要删去的行
		for(int i=k+1;i<equ;++i)
		{
			if(a[i][col]!=0)
			{
				for(int j=col;j<=var;++j)
					a[i][j]^=a[k][j];
			}
		}
	}
	for(int i = k; i<equ; i++)
	{
	    if(a[i][col]!=0)
            return -1;
	}
	return 1<<(var-k);
}
int main()
{
    ios::sync_with_stdio(false);
    int T;
    cin>>T;
    int n;
    while(T--)
    {
        memset(a,0,sizeof a);
        cin>>n;
        equ = var = n;
        for(int i = 0; i<n; i++)
            cin>>from[i];
        for(int i = 0; i<n; i++)
            cin>>to[i];
        while(true)
        {
            int x,y;
            cin>>x>>y;
            if(!x && !y)
                break;
            a[y-1][x-1] = 1;
        }
        for(int i = 0; i<n; i++)
        {
            a[i][i]  = 1;
            a[i][n] = from[i]^to[i];
        }
        int ans = Gauss();
        if(ans == -1)
            cout<<"Oh,it's impossible~!!"<<endl;
        else
            cout<<ans<<endl;
    }

    return 0;
}

 5.POJ-2947(高斯消元求解多元模线性方程组)

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.

题意:

 N种物品,M条记录,接写来M行,每行有K,Start,End,表述从星期Start到星期End,做了K件物品,接下来的K个数为物品的编号。求解每个物品加工时间,最后结果要求调整到3-9之间。

思路:

 设每种物品的加工时间为xi,容易建立方程\sum x_{i}\%7 = (Ed-St+7)\%7,高斯消元求解即可。

 代码:

#include <cstdio>
#include <stack>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#include <map>
#include <vector>
#include <queue>
#include <set>
#define eps 1e-8
typedef long long ll;
const double PI = acos(-1.0);
const int maxn = 305;
const int INF = 0x3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;
using namespace std;
int n,m;
int equ,var;
int a[maxn][maxn];
int x[maxn];
int trans(char *s)
{
    if(strcmp(s,"MON") == 0)
        return 1;
    if(strcmp(s,"TUE") == 0)
        return 2;
    if(strcmp(s,"WED") == 0)
        return 3;
    if(strcmp(s,"THU") == 0)
        return 4;
    if(strcmp(s,"FRI") == 0)
        return 5;
    if(strcmp(s,"SAT") == 0)
        return 6;
    return 7;
}
int gcd(int x, int y)
{
    if(y == 0)
        return x;
    return gcd(y,x%y);
}
int lcm(int x, int y)
{
    return x/gcd(x,y)*y;
}
int Gauss()
{
    int i,j;
    int row,col,max_r;// 当前这列绝对值最大的行;
    int LCM;
    int ta,tb;
    int tmp;
    for(row=0,col=0; row<m&&col<n; row++,col++)
    {
        // 枚举当前处理的行.
        // 找到该col列元素绝对值最大的那行与第row行交换.(为了在除法时减小误差)
        max_r=row;
        for(i=row+1; i<m; i++)
        {
            if(abs(a[i][col])>abs(a[max_r][col]))
                max_r=i;
        }
        if(max_r!=row)
        {
            // 与第row行交换
            for(j=row; j<n+1; j++)
                swap(a[row][j],a[max_r][j]);
        }
        if(a[row][col]==0)
        {
            // 说明该col列第row行以下全是0了,则处理当前行的下一列.
            row--;
            continue;
        }
        for(i=row+1; i<m; i++)
        {
            // 枚举要删去的行.
            if(a[i][col]!=0)
            {
                LCM=lcm(abs(a[i][col]),abs(a[row][col]));
                ta=LCM/abs(a[i][col]);
                tb=LCM/abs(a[row][col]);
                if(a[i][col]*a[row][col]<0) tb=-tb;//异号的情况是相加
                for(j=col; j<n+1; j++)
                {
                    a[i][j]=(((a[i][j]*ta-a[row][j]*tb)%7+7)%7);
                }
            }
        }
    }
    // 1. 无解的情况: 化简的增广阵中存在(0, 0, ..., a)这样的行(a != 0).
    for(i=row; i<m; i++)
    {
        if(a[i][col]!=0)  return -1;
    }
    // 2. 无穷解的情况: 在n * (n + 1)的增广阵中出现(0, 0, ..., 0)这样的行,即说明没有形成严格的上三角阵.
    // 且出现的行数即为自由变元的个数.
    if(row<n)
    {
        return n-row;
    }
     // 3. 唯一解的情况: 在n * (n + 1)的增广阵中形成严格的上三角阵.
    // 计算出Xn-1, Xn-2 ... X0.
    for(i=n-1; i>=0; i--)
    {
        tmp=a[i][n];//等式右边的数
        for(j=i+1; j<n; j++)
        {
            if(a[i][j]!=0) tmp-=a[i][j]*x[j];//把已知的解带入,减去,只剩下,一个未知的解
            tmp=(tmp%7+7)%7;
        }
        while(tmp%a[i][i]!=0)//外层每次循环都是为了求 a[i][i],因为它是每个方程中唯一一个未知的变量(求该方程时)
            tmp+=7;//因为天数不确定,而aug[i][i]必须得为整数才可以,周期为7
        x[i]=(tmp/a[i][i])%7;
    }
    return 0;
}
int main()
{
    //ios::sync_with_stdio(false);
    while(scanf("%d%d",&n,&m) != EOF)
    {
        if(!n && !m)
            break;
        memset(a,0,sizeof a);
        for(int i = 0; i<m; i++)
        {
            int k;
            scanf("%d",&k);
            char st[10],ed[10];
            scanf("%s %s",st,ed);
            a[i][n] = ((trans(ed)-trans(st)+1)%7+7)%7;
            while(k--)
            {
                int num;
                scanf("%d",&num);
                num--;
                a[i][num]++;
                a[i][num] %= 7;
            }
        }
        equ = m;
        var = n;
        int free_num = Gauss();
        if(free_num == 0)
        {
            for(int i = 0; i<n; i++)
            {
                if(x[i]<3)
                    x[i] += 7;

            }
            for(int i = 0; i<n-1; i++)
                printf("%d ",x[i]);
            printf("%d\n",x[n-1]);
        }
        else if(free_num == -1)
            puts("Inconsistent data.");
        else
            puts("Multiple solutions.");
    }

    return 0;
}

 6.POJ-1681(高斯消元解异或方程组)

There is a square wall which is made of n*n small square bricks. Some bricks are white while some bricks are yellow. Bob is a painter and he wants to paint all the bricks yellow. But there is something wrong with Bob's brush. Once he uses this brush to paint brick (i, j), the bricks at (i, j), (i-1, j), (i+1, j), (i, j-1) and (i, j+1) all change their color. Your task is to find the minimum number of bricks Bob should paint in order to make all the bricks yellow.

Input

The first line contains a single integer t (1 <= t <= 20) that indicates the number of test cases. Then follow the t cases. Each test case begins with a line contains an integer n (1 <= n <= 15), representing the size of wall. The next n lines represent the original wall. Each line contains n characters. The j-th character of the i-th line figures out the color of brick at position (i, j). We use a 'w' to express a white brick while a 'y' to express a yellow brick.

Output

For each case, output a line contains the minimum number of bricks Bob should paint. If Bob can't paint all the bricks yellow, print 'inf'.

Sample Input

2
3
yyy
yyy
yyy
5
wwwww
wwwww
wwwww
wwwww
wwwww

Sample Output

0
15

题意:

将所有的y变成w,按一个开关上下左右都要变,问最少按几个开关。 

 思路:

同上面,不再赘述。

 代码:

#include <cstdio>
#include <stack>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#include <map>
#include <vector>
#include <queue>
#include <set>
#define eps 1e-8
typedef long long ll;
const double PI = acos(-1.0);
const int maxn = 1e6;
const int INF = 0x3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;
using namespace std;
int a[305][305];
int dir[5][2] = {0,0,-1,0,1,0,0,-1,0,1};
int n;
void init()
{
    for(int i = 0; i<n; i++)
        for(int j = 0; j<n; j++)
            for(int k = 0; k<5; k++)
    {
        int x = i+dir[k][0];
        int y = j+dir[k][1];
        if(x>=0 && x<n && y>=0 && y<n)
            a[i*n+j][x*n+y] = 1;
    }
}
int Gauss()
{
    int i,j,k;
    for(i=0,j=0; i<n*n&&j<n*n; i++,j++)
    {
        k = i;
        for(;k<n*n;k++)
        {
            if(a[k][j])
                break;
        }
        if(i != k)
        {
            for(int t = j; t<=n*n; t++)
            {
                swap(a[i][t],a[k][t]);
            }
        }
        if(!a[i][j])
        {
            i--;
            continue;
        }
        for(k=i+1; k<n*n; k++)
        {
            if(a[k][j])
            {
                for(int t = j; t<=n*n; t++)
                    a[k][t] ^= a[i][t];
            }
        }
    }
    k = i;
    for(i = k; i<n*n; i++)
    {
        if(a[i][n*n])
            return 0;
    }
    for(i = k-1; i>=0; i--)
    {
        for(j = i+1; j<n*n; j++)
        {
            a[i][n*n] ^= (a[i][j]&a[j][n*n]);
        }
    }
    return 1;
}
int main()
{
    //ios::sync_with_stdio(false);
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        memset(a,0,sizeof a);
        init();
        for(int i = 0; i<n*n; i++)
        {
            char c;
            scanf(" %c",&c);
            if(c == 'w')
                a[i][n*n] = 1;
            else
                a[i][n*n] = 0;
        }
        int ans = Gauss();
        if(!ans)
        {
            puts("inf");
            continue;
        }
        int cnt = 0;
        for(int i = 0; i<n*n; i++)
        {
            if(a[i][n*n] == 1)
                cnt++;
        }
        cout<<cnt<<endl;
    }

    return 0;
}

 7.POJ - 2065(高斯消元解多元模线性方程组)

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, ...a n-1 the function f (k) = ∑ 0<=i<=n-1a ik i (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 <= a i < 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

题意:

 思路:

建立方程组联立求解即可。

代码:

#include <cstdio>
#include <stack>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#include <map>
#include <vector>
#include <queue>
#include <set>
#define eps 1e-8
typedef long long ll;
const double PI = acos(-1.0);
const int maxn = 105;
const int INF = 0x3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;
using namespace std;
char s[maxn];
int a[maxn][maxn];
int x[maxn];
bool free_x[maxn];
int n;
int mod;
int gcd(int x, int y)
{
    if(y == 0)
        return x;
    return gcd(y,x%y);
}
int lcm(int x, int y)
{
    return x/gcd(x,y)*y;
}
int Gauss()
{
    int i,j;
    int row,col,max_r;// 当前这列绝对值最大的行;
    int LCM;
    int ta,tb;
    int tmp;
    for(row=0,col=0; row<n&&col<n; row++,col++)
    {
        // 枚举当前处理的行.
        // 找到该col列元素绝对值最大的那行与第row行交换.(为了在除法时减小误差)
        max_r=row;
        for(i=row+1; i<n; i++)
        {
            if(abs(a[i][col])>abs(a[max_r][col]))
                max_r=i;
        }
        if(max_r!=row)
        {
            // 与第row行交换
            for(j=row; j<n+1; j++)
                swap(a[row][j],a[max_r][j]);
        }
        if(a[row][col]==0)
        {
            // 说明该col列第row行以下全是0了,则处理当前行的下一列.
            row--;
            continue;
        }
        for(i=row+1; i<n; i++)
        {
            // 枚举要删去的行.
            if(a[i][col]!=0)
            {
                LCM=lcm(abs(a[i][col]),abs(a[row][col]));
                ta=LCM/abs(a[i][col]);
                tb=LCM/abs(a[row][col]);
                if(a[i][col]*a[row][col]<0) tb=-tb;//异号的情况是相加
                for(j=col; j<n+1; j++)
                {
                    a[i][j]=(((a[i][j]*ta-a[row][j]*tb)%mod+mod)%mod);
                }
            }
        }
    }
    // 1. 无解的情况: 化简的增广阵中存在(0, 0, ..., a)这样的行(a != 0).
    for(i=row; i<n; i++)
    {
        if(a[i][col]!=0)  return -1;
    }
    // 2. 无穷解的情况: 在n * (n + 1)的增广阵中出现(0, 0, ..., 0)这样的行,即说明没有形成严格的上三角阵.
    // 且出现的行数即为自由变元的个数.
    if(row<n)
    {
        int free_index;
        int free_x_num;
        //自由变元有n-row个,即不确定的变元至少有var-k个.
        for(i = row-1; i>=0; i--)
        {
            // 用于判断该行中的不确定的变元的个数,如果超过1个,则无法求解,它们仍然为不确定的变元.
            free_x_num = 0;
            for(j = 0; j<n; j++)
            {
                if(a[i][j] && free_x[j])
                {
                    free_x_num++;
                    free_index = j;
                }
            }
            if(free_x_num>1)
                continue;
            tmp = a[i][n];
            for(j = 0; j<n; j++)
            {
                if(a[i][j] && free_index != j)
                    tmp -= a[i][j]*x[j]%mod;
                tmp = (tmp%mod+mod)%mod;
            }
            x[free_index] = tmp/a[i][free_index];
            free_x[free_index] = 0;

        }

        return n-row;
    }
     // 3. 唯一解的情况: 在n * (n + 1)的增广阵中形成严格的上三角阵.
    // 计算出Xn-1, Xn-2 ... X0.
    for(i=n-1; i>=0; i--)
    {
        tmp=a[i][n];//等式右边的数
        for(j=i+1; j<n; j++)
        {
            if(a[i][j]!=0) tmp-=a[i][j]*x[j];//把已知的解带入,减去,只剩下,一个未知的解
            tmp=(tmp%mod+mod)%mod;
        }
        while(tmp%a[i][i]!=0)//外层每次循环都是为了求 a[i][i],因为它是每个方程中唯一一个未知的变量(求该方程时)
            tmp+=mod;//因为不确定,而aug[i][i]必须得为整数才可以,周期为mod
        x[i]=(tmp/a[i][i])%mod;
    }
    return 0;
}
int main()
{
    //ios::sync_with_stdio(false);
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&mod);
        scanf("%s",s);
        n = strlen(s);
        for(int i = 0; i<n; i++)
        {
            if(s[i] == '*')
                a[i][n] = 0;
            else
                a[i][n] = (s[i]-'a'+1)%mod;
            //int tmp = 1;
            for(int j = 0; j<n; j++)
            {
                if(j == 0)
                    a[i][j] = 1%mod;
                else
                    a[i][j] = (a[i][j-1]*(i+1))%mod;
            }
        }
        int ans = Gauss();
        for(int i = 0; i<n; i++)
        {
            cout<<x[i];
            if(i<n-1)
                cout<<" ";
            else
                cout<<endl;
        }

    }
    return 0;
}

8.POJ-1753(高斯消元解决异或方程组)

Flip game is played on a rectangular 4x4 field with two-sided pieces placed on each of its 16 squares. One side of each piece is white and the other one is black and each piece is lying either it's black or white side up. Each round you flip 3 to 5 pieces, thus changing the color of their upper side from black to white and vice versa. The pieces to be flipped are chosen every round according to the following rules:

  1. Choose any one of the 16 pieces.
  2. Flip the chosen piece and also all adjacent pieces to the left, to the right, to the top, and to the bottom of the chosen piece (if there are any).


Consider the following position as an example:

bwbw
wwww
bbwb
bwwb
Here "b" denotes pieces lying their black side up and "w" denotes pieces lying their white side up. If we choose to flip the 1st piece from the 3rd row (this choice is shown at the picture), then the field will become:

bwbw
bwww
wwwb
wwwb
The goal of the game is to flip either all pieces white side up or all pieces black side up. You are to write a program that will search for the minimum number of rounds needed to achieve this goal.

Input

The input consists of 4 lines with 4 characters "w" or "b" each that denote game field position.

Output

Write to the output file a single integer number - the minimum number of rounds needed to achieve the goal of the game from the given position. If the goal is initially achieved, then write 0. If it's impossible to achieve the goal, then write the word "Impossible" (without quotes).

Sample Input

bwwb
bbwb
bwwb
bwww

Sample Output

4

题意:

与上面的差不多,但是这次目标状态变为全0或全1,求解按下最小开关数

思路:

不再赘述。

代码:

#include <algorithm>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <iomanip>
#include <stdio.h>
#include <string>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
#define eps 1e-10
#define LL __int64
#define INF 0x7ffffff
#define PI 3.1415926535898
#define zero(x) ((fabs(x)<eps)?0:x)
#define mod 2

const int maxn = 210;

using namespace std;

int a[maxn][maxn];
int x[maxn];
int equ, var;
int x1[maxn], x2[maxn];
int free_x[maxn];
int free_num;
int f[maxn];
char str;

int LCM(int a, int b)
{
    return (a/(__gcd(a, b)))*b;
}

int Gauss()
{
    int row, col, max_r;
    int num = 0;
    row = col = 0;
    while(row < equ && col < var)
    {
        max_r = row;
        for(int i = row+1; i < equ; i++)
            if(abs(a[i][col]) > abs(a[max_r][col])) max_r = i;
        if(max_r != row)
            for(int j = col; j <= var; j++) swap(a[row][j], a[max_r][j]);
        if(a[row][col] == 0)
        {
            free_x[num++] = col;
            col++;
            continue;
        }
        for(int i = row+1; i < equ; i++)
        {
            if(a[i][col] == 0) continue;
            int l = LCM(abs(a[row][col]), abs(a[i][col]));
            int ta = l/a[i][col];
            int tb = l/a[row][col];
            ///判断是否异号
            if(ta*tb < 0) tb *= -1;
            for(int j = col; j <= var; j++)
                a[i][j] = ((a[i][j]*ta - a[row][j]*tb)%mod + mod)%mod;
        }
        row++;
        col++;
    }
    for(int i = row; i < equ; i++)///无解的情况;
        if(a[i][col] != 0) return INF;
    if(var == row)
    {
        ///唯一解的情况,根据上三角阵,迭代求出每一次的值
        for(int i = var-1; i >= 0; i--)
        {
            int tmp = a[i][var];
            for(int j = i+1; j < var; j++)
                if(a[i][j] != 0) tmp = ((tmp-a[i][j]*x[j])%mod + mod)%mod;
            while(tmp%a[i][i] != 0)
                tmp += mod;
            x[i] = tmp/a[i][i]%mod;
        }
        int cnt = 0;
        for(int i = 0; i < 16; i++)
            cnt += x[i];
        return cnt;
    }
    int res = INF;
    int n = 1<<(var-row);
    int t = var-row;
    ///枚举变元
    for(int i = 0; i < n; i++)
    {
        int cnt = 0;
        for(int j = 0; j < t; j++)
        {
            if(i&(1<<j))
            {
                x[free_x[j]] = 1;
                cnt++;
            }
            else
                x[free_x[j]] = 0;
        }
        for(int j = row-1; j >= 0; j--)
        {
            int xx;
            for(xx = j; xx < var; xx++)
                if(a[j][xx]) break;
            x[xx] = a[j][var];
            for(int k = xx+1; k < var; k++)
                if(a[j][k]) x[xx] ^= x[k];
            cnt += x[xx];
        }
        res = min(res, cnt);
    }
    return res;
}

void init()
{
    equ = var = 16;
    memset(x, 0, sizeof(x));
    memset(a, 0, sizeof(a));
    for(int i = 0; i < 4; i++)
    {
        for(int j = 0; j < 4; j++)
        {
            int t = i*4+j;
            a[t][t] = 1;
            if(i-1 >= 0) a[(i-1)*4+j][t] = 1;
            if(i+1 < 4)  a[(i+1)*4+j][t] = 1;
            if(j-1 >= 0) a[i*4+j-1][t] = 1;
            if(j+1 < 4)  a[i*4+j+1][t] = 1;
        }
    }
}

int main()
{
    for(int i = 0; i < 4; i++)
    {
        for(int j = 0; j < 4; j++)
        {
            cin >>str;
            if(str == 'w')
                f[i*4+j] = 0;
            else
                f[i*4+j] = 1;
        }
    }
    for(int i = 0; i < 16; i++) x1[i] = 0;
    for(int i = 0; i < 16; i++) x2[i] = 1;
    init();
    for(int i = 0; i < 16; i++) a[i][16] = f[i]^x1[i];
    int flag1 = Gauss();
    init();
    for(int i = 0; i < 16; i++) a[i][16] = f[i]^x2[i];
    int flag2 = Gauss();
    if(flag1 == flag2 && flag1 == INF)
        cout<<"Impossible"<<endl;
    else
        cout<<min(flag1, flag2)<<endl;
    return 0;
}

9.POJ-3185(高斯消元求解异或方程组)

The cows have a line of 20 water bowls from which they drink. The bowls can be either right-side-up (properly oriented to serve refreshing cool water) or upside-down (a position which holds no water). They want all 20 water bowls to be right-side-up and thus use their wide snouts to flip bowls.

Their snouts, though, are so wide that they flip not only one bowl but also the bowls on either side of that bowl (a total of three or -- in the case of either end bowl -- two bowls).

Given the initial state of the bowls (1=undrinkable, 0=drinkable -- it even looks like a bowl), what is the minimum number of bowl flips necessary to turn all the bowls right-side-up?

Input

Line 1: A single line with 20 space-separated integers

Output

Line 1: The minimum number of bowl flips necessary to flip all the bowls right-side-up (i.e., to 0). For the inputs given, it will always be possible to find some combination of flips that will manipulate the bowls to 20 0's.

Sample Input

0 0 1 1 1 0 0 1 1 0 1 1 0 0 0 0 0 0 0 0

Sample Output

3

Hint

Explanation of the sample:

Flip bowls 4, 9, and 11 to make them all drinkable:
0 0 1 1 1 0 0 1 1 0 1 1 0 0 0 0 0 0 0 0 [initial state]
0 0 0 0 0 0 0 1 1 0 1 1 0 0 0 0 0 0 0 0 [after flipping bowl 4]
0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 [after flipping bowl 9]
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 [after flipping bowl 11]

题意:

求解变成全0至少需要按多少开关

 思路:

建立方程组后求解即可。

 代码:

 

/**

**/
#include <cstdio>
#include <stack>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#include <map>
#include <vector>
#include <queue>
#include <set>
#define eps 1e-8
typedef long long ll;
const double PI = acos(-1.0);
const int maxn = 1e6;
const int INF = 0x3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;
using namespace std;
int a[25][25];
int x[25];
int free_x[25];

// 高斯消元法解方程组(Gauss-Jordan elimination).(-2表示有浮点数解,但无整数解,
//-1表示无解,0表示唯一解,大于0表示无穷解,并返回自由变元的个数)
//有equ个方程,var个变元。增广矩阵行数为equ,分别为0到equ-1,列数为var+1,分别为0到var.
int Gauss(int equ,int var)
{
    int i,j,k;
    int max_r;// 当前这列绝对值最大的行.
    int col;//当前处理的列
    int ta,tb;
    int LCM;
    int temp;
    int free_index;
    int num=0;
    for(int i=0;i<=var;i++)
    {
        x[i]=0;
        free_x[i]=0;
    }
    //转换为阶梯阵.
    col=0; // 当前处理的列
    for(k = 0;k < equ && col < var;k++,col++)
    {// 枚举当前处理的行.
// 找到该col列元素绝对值最大的那行与第k行交换.(为了在除法时减小误差)
        max_r=k;
        for(i=k+1;i<equ;i++)
        {
            if(abs(a[i][col])>abs(a[max_r][col])) max_r=i;
        }
        if(max_r!=k)
        {// 与第k行交换.
            for(j=k;j<var+1;j++) swap(a[k][j],a[max_r][j]);
        }
        if(a[k][col]==0)
        {// 说明该col列第k行以下全是0了,则处理当前行的下一列.
            k--;
            free_x[num++]=col;
            continue;
        }
        for(i=k+1;i<equ;i++)
        {// 枚举要删去的行.
            if(a[i][col]!=0)
            {
              //  LCM = lcm(abs(a[i][col]),abs(a[k][col]));
              //  ta = LCM/abs(a[i][col]);
              //  tb = LCM/abs(a[k][col]);
              //  if(a[i][col]*a[k][col]<0)tb=-tb;//异号的情况是相加
                for(j=col;j<var+1;j++)
                {
                    a[i][j] ^= a[k][j];
                }
            }
        }
    }

    // 1. 无解的情况: 化简的增广阵中存在(0, 0, ..., a)这样的行(a != 0).
    for (i = k; i < equ; i++)
    { // 对于无穷解来说,如果要判断哪些是自由变元,那么初等行变换中的交换就会影响,则要记录交换.
        if (a[i][col] != 0) return -1;
    }
    int stat=1<<(var-k);//自由变元有 var-k 个
    int res=INF;
    for(i=0;i<stat;i++)//枚举所有变元
    {
        int cnt=0;
        int index=i;
        for(j=0;j<var-k;j++)
        {
            x[free_x[j]]=(index&1);
            if(x[free_x[j]]) cnt++;
            index>>=1;
        }
        for(j=k-1;j>=0;j--)
        {
            int tmp=a[j][var];
            for(int l=j+1;l<var;l++)
              if(a[j][l]) tmp^=x[l];
            x[j]=tmp;
            if(x[j])cnt++;
        }
        if(cnt<res)res=cnt;
    }
    return res;
}
void init()
{
    for(int i = 0; i<20; i++)
    {
        for(int j = 0; j<20; j++)
            a[i][j] = 0;
        a[i][i] = 1;
        if(i>0)
            a[i][i-1] = 1;
        if(i<19)
            a[i][i+1] = 1;
    }
}
int main()
{
   init();
    for(int i = 0; i<20; i++)
        scanf("%d",&a[i][20]);
    printf("%d\n",Gauss(20,20));
    return 0;
}
/**
0 0 1 1 1 0 0 1 1 0 1 1 0 0 0 0 0 0 0 0
**/

 10.POJ-1487(dfs+高斯消元)

Playing games is the most fun if other people take part. But other players are not always available if you need them, which led to the invention of single-player games. One of the most well-known examples is the infamous ``Solitaire'' packaged with Windows, probably responsible for more wasted hours in offices around the world than any other game.
The goal of a single-player game is usually to make ``moves'' until one reaches a final state of the game, which results in a win or loss, or a score assigned to that final state. Most players try to optimize the result of the game by employing good strategies. In this problem we are interested in what happens if one plays randomly. After all, these games are mostly used to waste time, and playing randomly achieves this goal as well as any other strategy.

Games can very compactly represented as (possibly infinite) trees. Every node of the tree repre- sents a possible game state. The root of the tree corresponds to the starting position of the game. For an inner node, its children are the game states to which one can move in a single move. The leaf nodes are the final states, and every one of them is assigned a number, which is the score one receives when ending up at that leaf.


Trees are defined using the following grammar.


Definition ::= Identifier "=" RealTree
RealTree ::= "("Tree +")"
Tree ::= Identifier | Integer | "("Tree +")"
Identifier ::= a|b|...|z
Integer ∈ {...,-3,-2,-1,0,1,2,3,...,}


By using a Definition, the RealTree on the right-hand side of the equation is assigned to the Identifier on the left. A RealTree consists of a root node and one or more children, given as a sequence enclosed in brackets. And a Tree is either

. the tree represented by a given Identifier, or

. a leaf node, represented by a single Integer, or

. an inner node, represented by a sequence of one or more Trees (its children), enclosed in brackets.

Your goal is to compute the expected score, if one plays randomly, i.e. at each inner node selects one of the children uniformly at random. This expected score is well-defined even for the infinite trees definable in our framework as long as the probability that the game ends (playing randomly) is 1.

Input

The input file contains several gametree descriptions. Each description starts with a line containing the number n of identifiers used in the description. The identifiers used will be the first n lowercase letters of the alphabet. The following n lines contain the definitions of these identifiers (in the order a, b, ...). Each definition may contain arbitrary whitespace (but of course there will be no spaces within a single integer). The right hand side of a definition will contain only identifiers from the first n lowercase letters. The inputs ends with a test case starting with n = 0. This test case should not be processed.

Output

For each gametree description in the input, first output the number of the game. Then, for all n identifiers in the order a, b, ..., output the following. If an identifier represents a gametree for which the probability of finishing the game is 1, print the expected score (when playing randomly). This value should be exact to three digits to the right of the decimal point.

If the game described by the variable does not end with probability 1, print ``Expected score of id undefined'' instead. Output a blank line after each test case.

Sample Input

1
a = ((1 7) 6 ((8 3) 4))
2
a = (1 b)
b = (4 a)
1
a = (a a a)
0

Sample Output

Game 1
Expected score for a = 4.917

Game 2
Expected score for a = 2.000
Expected score for b = 3.000

Game 3
Expected score for a undefined

题意:

给定树后求解价值期望。

思路:

符号处理跑这个结构,最后高斯消元求解方程组。真的恶心,直接粘了题解。

代码:

/**

**/
#include <cstdio>
#include <stack>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#include <map>
#include <vector>
#include <queue>
#include <set>
#define eps 1e-8
typedef long long ll;
const double PI = acos(-1.0);
const int maxn = 1005;
const int INF = 0x3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;
using namespace std;
double a[maxn][maxn],x[maxn];
int free_x[maxn];
int equ,var;

int Gauss()
{

    int i,j,k,col,max_r;
    memset(free_x,0,sizeof(free_x));
    for(k=0,col=0;k<equ&&col<var;k++,col++)
    {
        max_r=k;
        for(i=k+1;i<equ;i++)
            if(fabs(a[i][col])>fabs(a[max_r][col])) max_r=i;

        if(fabs(a[max_r][col]) < eps)
        {
            k--;
            continue;
        }

        if(k!=max_r)
            for(j=col;j<=var;j++) swap(a[k][j],a[max_r][j]);

        for(int i = k+1; i < equ; ++i)
        {
            if(fabs(a[i][col]) <= eps) continue;
            for(int j = col+1; j <= var; ++j)
                a[i][j] = a[i][j]-a[i][col]/a[k][col]*a[k][j];

            a[i][col] = 0;
        }
    }

    for(int i = k; i < equ; ++i)
        if(fabs(a[i][var]) >= eps) return -1;

    if(k < equ)
    {
        for(int i = k-1; i >= 0; --i)
        {
            int id,cnt = 0;
            for(int j = 0; j < var; ++j)
            {
                if(fabs(a[i][j]) <= eps) continue;
                if(free_x[j]) continue;
                cnt++;
                id = j;
            }
            if(cnt > 1) continue;

            double tmp = a[i][var];

            for(int j = var-1; j >= 0; --j)
            {
                if(fabs(a[i][j]) > eps && j != id) tmp -= a[i][j]*x[j];
            }

            x[id] = tmp/a[i][id];
            free_x[id] = 1;
        }

        return equ-k;
    }

    for(int i = equ-1; i >= 0; --i)
    {
        double tmp = a[i][var];

        for(int j = var-1; j > i; --j)
        {
            tmp -= a[i][j]*x[j];
        }

        x[i] = tmp/a[i][i];
    }

    return 0;
}

char str[2333];

void dfs(int pos,int l,int r,double x)
{
    int per = 0;
    int pi = 0;

    bool f = 1;
    for(int i = l; i <= r; ++i)
    {
        if(str[i] == ' ') continue;
        per++;
        if(str[i] == '(')
        {
            f = 0;
            ++i;
            pi = 1;
            while(pi)
            {
                if(str[i] == '(') pi++;
                else if(str[i] == ')') pi--;
                ++i;
            }
        }
        else while(str[i] != ' ' && str[i] != '(' && str[i] != ')' && i <= r) ++i;
        --i;
    }
    x /= per;
    int st,en;

    if(f && per == 1)
    {
        for(int i = l; i <= r; ++i)
        {
            if('a' <= str[i] && str[i] <= 'z')
            {
                a[pos][str[i]-'a'] -= x;
                return;
            }
        }

        int tmp;
        sscanf(str+l,"%d",&tmp);
        a[pos][var] += x*tmp;
        return;
    }

    for(int i = l; i <= r; ++i)
    {
        if(str[i] == ' ') continue;
        st = i;

        if(str[i] == '(')
        {
            ++i;
            pi = 1;
            while(pi)
            {
                if(str[i] == '(') pi++;
                else if(str[i] == ')') pi--;
                ++i;
            }
            dfs(pos,st+1,i-2,x);
        }
        else
        {
            while(str[i] != ' ' && str[i] != '(' && str[i] != ')' && i <= r) ++i;
            dfs(pos,st,i-1,x);
        }
        --i;
    }
}

void init(int n)
{
    equ = var = n;
    memset(a,0,sizeof(a));

    for(int i = 0; i < n; ++i)
    {
        gets(str);

        int pos = 0;
        a[str[pos]-'a'][str[pos]-'a'] = 1;
        pos++;
        while(str[pos] == ' ' || str[pos] == '=') pos++;
        dfs(i,pos,strlen(str)-1,1);
    }
}

int main()
{
    //fread("in.in");
    //fwrite("my.out");

    int n,z = 1;

    while(~scanf("%d",&n) && n)
    {
        getchar();
        init(n);

        int t = Gauss();

        printf("Game %d\n",z++);
        for(int i = 0; i < n; ++i)
        {
            printf("Expected score for %c ",'a'+i);
            if(t == -1 || (t && !free_x[i])) puts("undefined");
            else printf("= %.3f\n",x[i]);
        }

        puts("");
    }

    return 0;
}

11.HDU-3359(高斯消元求解线性方程组)

Image blurring occurs when the object being captured is out of the camera's focus. The top two figures on the right are an example of an image and its blurred version. Restoring the original image given only the blurred version is one of the most interesting topics in image processing. This process is called deblurring, which will be your task for this problem.
In this problem, all images are in grey-scale (no colours). Images are represented as a 2 dimensional matrix of real numbers, where each cell corresponds to the brightness of the corresponding pixel. Although not mathematically accurate, one way to describe a blurred image is through averaging all the pixels that are within (less than or equal to) a certain Manhattan distance?from each pixel (including the pixel itself ). Here's an example of how to calculate the blurring of a 3x3 image with a blurring distance of 1:


Given the blurred version of an image, we are interested in reconstructing the original version assuming that the image was blurred as explained above.

  

 

Input

Input consists of several test cases. Each case is specified on H + 1 lines. The first line specifies three non negative integers specifying the width W, the height H of the blurred image and the blurring distance D respectively where (1<= W,H <= 10) and (D <= min(W/2,H/2)). The remaining H lines specify the gray-level of each pixel in the blurred image. Each line specifies W non-negative real numbers given up to the 2nd decimal place. The value of all the given real numbers will be less than 100.
Zero or more lines (made entirely of white spaces) may appear between cases. The last line of the input file consists of three zeros.

Output

For each test case, print a W * H matrix of real numbers specifying the deblurred version of the image. Each element in the matrix should be approximated to 2 decimal places and right justified in a field of width 8. Separate the output of each two consecutive test cases by an empty line. Do not print an empty line after the last test case. It is guaranteed that there is exactly one unique solution for every test case.

Sample Input

2 2 1
1 1
1 1

3 3 1
19 14 20
12 15 18
13 14 16

4 4 2
14 15 14 15
14 15 14 15
14 15 14 15
14 15 14 15

0 0 0

Sample Output

    1.00    1.00
    1.00    1.00

    2.00   30.00   17.00
   25.00    7.00   13.00
   14.00    0.00   35.00

    1.00   27.00    2.00   28.00
   21.00   12.00   17.00    8.00
   21.00   12.00   17.00    8.00
    1.00   27.00    2.00   28.00

        
  

Hint

The Manhattan Distance (sometimes called the Taxicab distance) between
two points is the sum of the (absolute) difference of their coordinates. 
The grid on the lower right illustrates the Manhattan distances from the grayed cell.

 题意:

给你一个n*m矩阵,aij代表原矩阵x中与xij曼哈顿距离不超过d的所有数的平均值,求解x

 思路:

根据矩阵建立方程组求解就可以。注意输出格式,恶心得不行。

代码:

 

/**

**/
#include <cstdio>
#include <stack>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#include <map>
#include <vector>
#include <queue>
#include <set>
#define eps 1e-8
typedef long long ll;
const double PI = acos(-1.0);
const int maxn = 106;
const int INF = 0x3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;
using namespace std;
double num[maxn][maxn];
double a[maxn][maxn],x[maxn];
int free_x[maxn];
int equ,var;
int Gauss()
{

    int i,j,k,col,max_r;
    memset(free_x,0,sizeof(free_x));
    for(k=0,col=0;k<equ&&col<var;k++,col++)
    {
        max_r=k;
        for(i=k+1;i<equ;i++)
            if(fabs(a[i][col])>fabs(a[max_r][col])) max_r=i;

        if(fabs(a[max_r][col]) < eps)
        {
            k--;
            continue;
        }

        if(k!=max_r)
            for(j=col;j<=var;j++) swap(a[k][j],a[max_r][j]);

        for(int i = k+1; i < equ; ++i)
        {
            if(fabs(a[i][col]) <= eps) continue;
            for(int j = col+1; j <= var; ++j)
                a[i][j] = a[i][j]-a[i][col]/a[k][col]*a[k][j];

            a[i][col] = 0;
        }
    }

    for(int i = k; i < equ; ++i)
        if(fabs(a[i][var]) >= eps) return -1;

    if(k < equ)
    {
        for(int i = k-1; i >= 0; --i)
        {
            int id,cnt = 0;
            for(int j = 0; j < var; ++j)
            {
                if(fabs(a[i][j]) <= eps) continue;
                if(free_x[j]) continue;
                cnt++;
                id = j;
            }
            if(cnt > 1) continue;

            double tmp = a[i][var];

            for(int j = var-1; j >= 0; --j)
            {
                if(fabs(a[i][j]) > eps && j != id) tmp -= a[i][j]*x[j];
            }

            x[id] = tmp/a[i][id];
            free_x[id] = 1;
        }

        return equ-k;
    }

    for(int i = equ-1; i >= 0; --i)
    {
        double tmp = a[i][var];

        for(int j = var-1; j > i; --j)
        {
            tmp -= a[i][j]*x[j];
        }

        x[i] = tmp/a[i][i];
    }

    return 0;
}

int main()
{
    //ios::sync_with_stdio(false);
    int m,n,d;
    int tt = 0;
    while(scanf("%d%d%d",&m,&n,&d)!=EOF)
    {
        if(m == n && m == d && d == 0)
            break;
        if(tt++)
            puts("");
        memset(a,0,sizeof a);
        for(int i = 0; i<n; i++)
            for(int j = 0; j<m; j++)
                scanf("%lf",&num[i][j]);
        for(int i1 = 0; i1<n; i1++)
            for(int i2 = 0; i2<m; i2++)
        {
            int cnt = 0;
            for(int i3 = 0; i3<n; i3++)
                for(int i4 = 0; i4<m; i4++)
            {
                if(abs(i1-i3)+abs(i2-i4)<=d)
                {
                    a[i1*m+i2][i3*m+i4] = 1;
                    cnt++;
                }
            }
            a[i1*m+i2][n*m] = num[i1][i2]*cnt;
        }
        equ = n*m;
        var = n*m;
        Gauss();
        for(int i = 0; i < n*m; i++)
        {
            if(i % m == m-1)
                printf("%8.2lf\n", x[i]);
            else
                printf("%8.2lf", x[i]);
        }
    }
    return 0;
}

 12.HDU-3949(线性基)

XOR is a kind of bit operator, we define that as follow: for two binary base number A and B, let C=A XOR B, then for each bit of C, we can get its value by check the digit of corresponding position in A and B. And for each digit, 1 XOR 1 = 0, 1 XOR 0 = 1, 0 XOR 1 = 1, 0 XOR 0 = 0. And we simply write this operator as ^, like 3 ^ 1 = 2,4 ^ 3 = 7. XOR is an amazing operator and this is a question about XOR. We can choose several numbers and do XOR operatorion to them one by one, then we get another number. For example, if we choose 2,3 and 4, we can get 2^3^4=5. Now, you are given N numbers, and you can choose some of them(even a single number) to do XOR on them, and you can get many different numbers. Now I want you tell me which number is the K-th smallest number among them.

Input

First line of the input is a single integer T(T<=30), indicates there are T test cases.
For each test case, the first line is an integer N(1<=N<=10000), the number of numbers below. The second line contains N integers (each number is between 1 and 10^18). The third line is a number Q(1<=Q<=10000), the number of queries. The fourth line contains Q numbers(each number is between 1 and 10^18) K1,K2,......KQ.

Output

For each test case,first output Case #C: in a single line,C means the number of the test case which is from 1 to T. Then for each query, you should output a single line contains the Ki-th smallest number in them, if there are less than Ki different numbers, output -1.

Sample Input

2
2
1 2
4
1 2 3 4
3
1 2 3
5
1 2 3 4 5

Sample Output

Case #1:
1
2
3
-1
Case #2:
0
1
2
3
-1


        
  

Hint

If you choose a single number, the result you get is the number you choose.
Using long long instead of int because of the result may exceed 2^31-1.

题意:

求解a1~an异或所得第k大的数

思路:

事实上我们可以先把ai的每一位取出,然后通过异或的高斯消元,可以解出一个类似于上三角的矩阵,然后就可以知道异或后得到的结果可以是哪几位为1(非自由元个数cnt),注意如果n = cnt,则无法得到0,即能构成1~2^n-1共2^n-1个数,否则则能构成0~2^cnt-1共2^cnt个数,需要判断一下是否存在第k大的数。随后将k进行2进制展开,对相应的位数取1即可。

代码:

#include <cstdio>
#include <stack>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#include <map>
#include <vector>
#include <queue>
#include <set>
#define eps 1e-8
typedef long long ll;
const double PI = acos(-1.0);
const int maxn = 1e6;
const int INF = 0x3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;
using namespace std;
int cnt;
ll a[maxn],p[100];
void Gauss(int n)
{
    memset(p,0,sizeof p);
    for(int i = 1; i<=n; i++)
        for(int j = 63; j>=0; j--)
        {
            if(!(a[i]>>j)&1)
                continue;
            if(p[j])
                a[i] ^= p[j];
            else
            {
                p[j] = a[i];
                break;
            }

        }
    for(int i = 63; i>=0; i--)
    {
        if(!p[i])
            continue;
        for(int j = i+1; j<=62; j++)
        {
            if((p[j]>>i)&1)
                p[j] ^= p[i];
        }
    }
    cnt = 0;
    for(int j = 0; j<63; j++)
    {
        if(p[j])
            p[cnt++] = p[j];
    }
}
int main()
{
    //ios::sync_with_stdio(false);
    int T;
    int tt = 1;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        scanf("%d",&n);
        for(int i = 1; i<=n; i++)
            scanf("%lld",&a[i]);
        Gauss(n);
        printf("Case #%d:\n",tt++);
        int m;
        scanf("%d",&m);
        while(m--)
        {
            ll k;
            scanf("%lld",&k);
            if(n!=cnt)
                k--;
            if((1ll<<cnt)<=k)
            {
                puts("-1");
                continue;
            }
            ll ans = 0;
            for(int i = 0; i<=63; i++)
            {
                if((k>>i)&1)
                    ans ^= p[i];
            }
            printf("%lld\n",ans);
        }
    }
    return 0;
}

13.CodeForces-1100F(前缀线性基+贪心)

Ivan loves burgers and spending money. There are nn burger joints on the street where Ivan lives. Ivan has qq friends, and the ii-th friend suggested to meet at the joint lili and walk to the joint riri (li≤ri)(li≤ri). While strolling with the ii-th friend Ivan can visit all joints xx which satisfy li≤x≤rili≤x≤ri.

For each joint Ivan knows the cost of the most expensive burger in it, it costs cici burles. Ivan wants to visit some subset of joints on his way, in each of them he will buy the most expensive burger and spend the most money. But there is a small issue: his card broke and instead of charging him for purchases, the amount of money on it changes as follows.

If Ivan had dd burles before the purchase and he spent cc burles at the joint, then after the purchase he would have d⊕cd⊕c burles, where ⊕⊕ denotes the bitwise XOR operation.

Currently Ivan has 22100−122100−1 burles and he wants to go out for a walk. Help him to determine the maximal amount of burles he can spend if he goes for a walk with the friend ii. The amount of burles he spends is defined as the difference between the initial amount on his account and the final account.

Input

The first line contains one integer nn (1≤n≤5000001≤n≤500000) — the number of burger shops.

The next line contains nn integers c1,c2,…,cnc1,c2,…,cn (0≤ci≤1060≤ci≤106), where cici — the cost of the most expensive burger in the burger joint ii.

The third line contains one integer qq (1≤q≤5000001≤q≤500000) — the number of Ivan's friends.

Each of the next qq lines contain two integers lili and riri (1≤li≤ri≤n1≤li≤ri≤n) — pairs of numbers of burger shops between which Ivan will walk.

Output

Output qq lines, ii-th of which containing the maximum amount of money Ivan can spend with the friend ii.

Examples

Input

4
7 2 3 4
3
1 4
2 3
1 3

Output

7
3
7

Input

5
12 14 23 13 7
15
1 1
1 2
1 3
1 4
1 5
2 2
2 3
2 4
2 5
3 3
3 4
3 5
4 4
4 5
5 5

Output

12
14
27
27
31
14
25
26
30
23
26
29
13
13
7

Note

In the first test, in order to spend the maximum amount of money with the first and third friends, Ivan just needs to go into the first burger. With a second friend, Ivan just go to the third burger.

In the second test for a third friend (who is going to walk from the first to the third burger), there are only 8 options to spend money — 00, 1212, 1414, 2323, 12⊕14=212⊕14=2, 14⊕23=2514⊕23=25, 12⊕23=2712⊕23=27, 12⊕14⊕23=2012⊕14⊕23=20. The maximum amount of money it turns out to spend, if you go to the first and third burger — 12⊕23=2712⊕23=27.

题意:

求解区间l~r的最大异或和

思路:

我们不妨记录每次插入一个数后前缀线性基的状态和插入第j个数后,能使第i位为1的元素的最大下标。

贪心地维护序列的前缀线性基 (上三角形态),对于每个线性基,将出现位置靠右的数字尽可能地放在高位,也就是说在插入新数字的时候,要同时记录对应位置上数字的出现位置,并且在找到可以插入的位置的时候,如果新数字比位置上原来的数字更靠右,就将该位置上原来的数字向低位推。在求最大值的时候,从高位向低位遍历,如果该位上的数字出现在询问中区间左端点的右侧且可以使答案变大,就异或到答案里。对于线性基的每一位,与它异或过的线性基更高位置上的数字肯定都出现在它右侧 (否则它就会被插入在那个位置了),因此做法的正确性显然。

代码:

#include <cstdio>
#include <stack>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#include <map>
#include <vector>
#include <queue>
#include <set>
#define eps 1e-8
typedef long long ll;
const double PI = acos(-1.0);
const int maxn = 1e6+5;
const int INF = 0x3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;
using namespace std;
int a[maxn][32];//前缀线性基
int pos[maxn][32];//第i位是1对应哪个元素
void Insert(int id, int t, int p)
{
    for(int j =31; j>=0; j--)
    {
        if(!(t&(1<<j)))
            continue;
        if(!a[j])
        {
            a[id][j] = t;
            pos[id][j] = p;
            break;
        }
        if(pos[id][j]<p)
        {
            swap(pos[id][j],p);
            swap(a[id][j],t);
        }
        t ^= a[id][j];
    }
}
int main()
{
    //ios::sync_with_stdio(false);
    int n,m;
    scanf("%d",&n);
    for(int i = 1; i<=n; i++)
    {
        int x;
        scanf("%d",&x);
        for(int j = 31; j>=0; j--)
        {
            pos[i][j] = pos[i-1][j];
            a[i][j] = a[i-1][j];
        }
        Insert(i,x,i);
    }
    scanf("%d",&m);
    while(m--)
    {
        int ans = 0;
        int l,r;
        scanf("%d%d",&l,&r);
        if(l>r)
            swap(l,r);
        ans = 0;
        for(int j = 31; j>=0; j--)
        {
            if(pos[r][j]<l)
                continue;
            ans = max(ans,ans^a[r][j]);
        }
        printf("%d\n",ans);
    }
    return 0;
}

 14.HDU-6579(前缀线性基+贪心)

There is an integer sequence aa of length nn and there are two kinds of operations:

  • 0 l r: select some numbers from al...aral...ar so that their xor sum is maximum, and print the maximum value.
  • 1 x: append xx to the end of the sequence and let n=n+1n=n+1.

 

Input

There are multiple test cases. The first line of input contains an integer T(T≤10)T(T≤10), indicating the number of test cases.
For each test case:
The first line contains two integers n,m(1≤n≤5×105,1≤m≤5×105)n,m(1≤n≤5×105,1≤m≤5×105), the number of integers initially in the sequence and the number of operations.
The second line contains nn integers a1,a2,...,an(0≤ai<230)a1,a2,...,an(0≤ai<230), denoting the initial sequence.
Each of the next mm lines contains one of the operations given above.
It's guaranteed that ∑n≤106,∑m≤106,0≤x<230∑n≤106,∑m≤106,0≤x<230.
And operations will be encrypted. You need to decode the operations as follows, where lastans denotes the answer to the last type 0 operation and is initially zero:
For every type 0 operation, let l=(l xor lastans)mod n + 1, r=(r xor lastans)mod n + 1, and then swap(l, r) if l>r.
For every type 1 operation, let x=x xor lastans.

Output

For each type 0 operation, please output the maximum xor sum in a single line.

Sample Input

1
3 3
0 1 2
0 1 1
1 3
0 3 4

Sample Output

1
3

题意:

与上题一样,加了一个插入操作。

思路

与上题一样,但此题需要从第31位开始遍历。

代码:

#include <cstdio>
#include <stack>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#include <map>
#include <vector>
#include <queue>
#include <set>
#define eps 1e-8
typedef long long ll;
const double PI = acos(-1.0);
const int maxn = 1e6+5;
const int INF = 0x3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;
using namespace std;
int a[maxn][32];//前缀线性基
int pos[maxn][32];//第i位是1对应哪个元素
void Insert(int id, int t, int p)
{
    for(int j =31; j>=0; j--)
    {
        if(!(t&(1<<j)))
            continue;
        if(!a[j])
        {
            a[id][j] = t;
            pos[id][j] = p;
            break;
        }
        if(pos[id][j]<p)
        {
            swap(pos[id][j],p);
            swap(a[id][j],t);
        }
        t ^= a[id][j];
    }
}
int main()
{
    //ios::sync_with_stdio(false);
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i = 1; i<=n; i++)
        {
            int x;
            scanf("%d",&x);
            for(int j = 31; j>=0; j--)
            {
                pos[i][j] = pos[i-1][j];
                a[i][j] = a[i-1][j];
            }
            Insert(i,x,i);
        }
        int ans = 0;
        while(m--)
        {
            int op;
            scanf("%d",&op);
            if(op)
            {
                int x;
                scanf("%d",&x);
                x ^= ans;
                n++;
                for(int j = 31; j>=0; j--)
                {
                    pos[n][j] =  pos[n-1][j];
                    a[n][j] = a[n-1][j];
                }
                Insert(n,x,n);
            }
            else
            {
                int l,r;
                scanf("%d%d",&l,&r);
                l = (l^ans)%n+1;
                r = (r^ans)%n+1;
                if(l>r)
                    swap(l,r);
                ans = 0;
                for(int j = 31; j>=0; j--)
                {
                    if(pos[r][j]<l)
                        continue;
                    ans = max(ans,ans^a[r][j]);
                }
                printf("%d\n",ans);
            }
        }
    }
    return 0;
}

15.HDU-2449(java大数跑高斯消元)

Li Zhixiang have already been in “Friendship” ocean-going freighter for three months. The excitement has gradually disappeared. He stands on the board, holding the railing and watching the dazzling ocean in the sun silently. Day after day, the same scenery is monotonous and tasteless, even the merry seagulls following the freighter cannot arouse his interest. Hearing the footsteps behind, he turns back to see the old captain is coming towards him. The captain has understood his idea, however, he starts a new topic with the young man.

“Do you know how far our voyage is?” The captain asks. Li Zhixiang feels ashamed because he can not answer. Then the captain says with a smile, “5050 miles. Do you still remember the story of 5050?” This time the young man really blushes. The old captain continues saying:” You definitely know the story of 5050. When the German mathematician, “the prince of mathematicians”, Gauss was 10 years old …” Young man remembers this story and goes on to tell, “ When Gauss was 10 years old, he could add a list of integers from 1 to 100 in a few seconds, which shocked the teachers.” The old captain adds, “Gauss has many other stories like this. When he entered the university at the age of 17, he was able to construct heptadecagon by compass and straightedge. His university teachers were also impressed by his ability. Not only could college graduate students fail to do it, but also they felt hard to understand Gauss’s constructing process.”

At this time, vice-captain greets the old captain. The old captain says to Li Zhixiang: “Come over to my office tonight, let’s continue the conversation.” It is still calm and tranquil in the evening. The freighter travels smoothly on the sea in the silver moonlight. The captain tells the young man the following words.
  
Among the mathematicians through the ages, there are three greatest mathematicians: Archimedes, Newton and Gauss. Most of Gauss’s mathematical achievements are difficult to understand. Nevertheless, there are some comparatively easy. For instance, when it comes to solving multivariate system of linear equations, there is a solution called “Gauss Elimination”. In the navigation business, many problems can be solved by “Gauss elimination”. If you are interested in it, I will show you a simple question. Try it.”

Input

There are several test cases. In the first line of each case, a number n indicates that there are n equations. The following n lines, each line has n+1 numbers, ai1,ai2,ai3…..ain, bi(1<= i <=n), these numbers indicate the coefficients of systems of the equations. ai1*x1+ai2*x2+......ain*xn=bi. Input is terminated by the end of file.
 

Output

For each given systems of equations, if there are solutions, output n solutions in the order of appearance in the equations(n<=100), each solution number is in one line. If solution is not integer, show it in fraction. If no solution, output “No solution.” Leave a blank line after each case.

Sample Input

2
1000000000000000000000000 1000000000000000000000000 1000000000000000000000000
-1000000000000000000000000 1000000000000000000000000 0
1
0 4

Sample Output

1/2
1/2

No solution.

题意:

求解Ax = B,解的小数输出a/b的形式

思路:

用java大数跑就行。

//java暴力解方程
import java.util.*;
import java.math.*;

public class Main {
    public static BigInteger g[][] = new BigInteger[110][110];

    public static boolean Gauss(int n) {
        BigInteger tmp, a, b;
        int i, j, k;
        for (i = 0; i < n; i++) {
            for (j = i; j < n; j++) {
                if (g[j][i].compareTo(BigInteger.ZERO) != 0)
                    break;
            }
            if (j >= n)
                return false;
            if (j != i) {
                for (k = 0; k <= n; k++) {
                    tmp = g[i][k];
                    g[i][k] = g[j][k];
                    g[j][k] = tmp;
                }
            }
            a = g[i][i];
            for (j = i + 1; j < n; j++) {
                if (g[j][i].compareTo(BigInteger.ZERO) != 0) {
                    b = g[j][i];
                    for (k = i; k <= n; k++) {
                        g[j][k] = g[j][k].multiply(a).subtract(
                                g[i][k].multiply(b));
                    }
                }
            }
        }
        return true;
    }

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        BigInteger x[] = new BigInteger[110];
        BigInteger y[] = new BigInteger[110];
        BigInteger tmp, up, down;
        int n, i, j;
        boolean neg;
        while (in.hasNext()) {
            n = in.nextInt();
            for (i = 0; i < n; i++) {
                for (j = 0; j <= n; j++)
                    g[i][j] = in.nextBigInteger();
            }
            if (Gauss(n)) {
                for (i = n - 1; i >= 0; i--) {
                    up = BigInteger.ZERO;
                    down = BigInteger.ONE;
                    for (j = i + 1; j < n; j++) {
                        up = y[j].multiply(up).add(
                                g[i][j].multiply(x[j].multiply(down)));
                        down = y[j].multiply(down);
                    }
                    up = g[i][n].multiply(down).subtract(up);
                    down = g[i][i].multiply(down);
                    if (up.multiply(down).compareTo(BigInteger.ZERO) < 0)
                        neg = true;
                    else
                        neg = false;
                    up = up.abs();
                    down = down.abs();
                    tmp = up.gcd(down);
                    x[i] = up.divide(tmp);
                    y[i] = down.divide(tmp);
                    if (neg)
                        x[i] = x[i].negate();
                }
                for (i = 0; i < n; i++) {
                    if (x[i].mod(y[i]).compareTo(BigInteger.ZERO) == 0)
                        System.out.println(x[i].divide(y[i]));
                    else
                        System.out.println(x[i] + "/" + y[i]);
                }
            } else
                System.out.println("No solution.");
            System.out.println();
        }
    }
}

 

 

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值