zoukankan      html  css  js  c++  java
  • 高斯消元 hdu5833,hdu3364,hihocoder1195

    hdu5833

    刘汝佳训练指南160页原题

    题意:给300个数,选任意个数相乘,问多少种方法可以得到完全平方数(每个数LL范围,保证每个数的质因子不超过2000)
    一点废话:
    从提示可以看出,显然第一步分解质因数,由于每个数只能乘0或1次,所以4和16对于结果是等价的(3和27也是),统计每个数字的质因子个数然后模2,我们只需要最后每个质因子的指数是个偶数就行了,这里既然只有0或1,不如直接用异或来算,
    则列出线性方程组:MaxP个方程(MaxP为用到的质因数个数):
    每个方程n个未知数,分别代表每个数,每个数的该质因子加起来为偶数
    然后可以套个高斯消元的板,或者简单的矩阵变换几次就可以了
    我这里参考了刘汝佳训练指南160页的代码
    (mdzz,原题,比赛的时候还有人讨论原题复制代码会不会被查重)

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cmath>
    #include <string>
    #include <cstring>
    using namespace std;
    typedef long long LL;
    const LL MOD = 1000000007;
    const LL N = 333,PN = 2007;
    int P,MaxP,n;
    LL p[N];
    
    struct matrix{
        LL a[N][N];
        int row,col;
        matrix():row(N),col(N){
            memset(a,0,sizeof(a));
        }
        matrix(int x,int y):row(x),col(y){
            memset(a,0,sizeof(a));
        }
        LL* operator [] (int x){
            return a[x];
        }
        void print(){
            for (int i=0;i<=MaxP;i++){
                for (int j=0;j<n;j++)
                    printf("%I64d ",a[i][j]);
                puts("");
            }
        }
    }a;
    
    void getPrime(){
        P=0;
        bool isPrime[PN];
        memset(isPrime,1,sizeof(isPrime));
        for (LL i=2;i<PN;i++){
            if(isPrime[i]) p[P++] = i;
            for (LL j=0;j<P&&p[j]*i<PN;j++){
                isPrime[i*p[j]] = 0;
                if (i%p[j]==0) break;
            }
        }
    }
    
    void getMatrix() {
        MaxP = 0;
        LL x;
        for (int i=0;i<n;i++) {
            scanf("%I64d",&x);
            for (int j=0;j<P&&p[j]<=x;j++)if(!(x%p[j])){
                MaxP = max(MaxP,j);
                while (x % p[j] == 0) {
                    a[j][i] ^= 1;
                    x /= p[j];
                }
            }
        }
    }
    
    int Rank(int m,int n){
        int i=0,j=0;
        for (; i<m && j<n ;j++){
            int r = i;
            for (int k=i;k<m;k++)if(a[k][j]){r=k;break;}
            if (a[r][j]){
                if (r!=i)for(int k=0;k<=n;k++)swap(a[r][k],a[i][k]);
                for (int u=i+1;u<m;u++)if (a[u][j])
                    for (int k=i;k<=n;k++)a[u][k] ^= a[i][k];
                i++;
            }
        }
        return i;
    }
    
    int main(){
        //freopen("fuck.in","r",stdin);
        int T;
        LL x;
        scanf("%d",&T);
        getPrime();
        for (int cas=1;cas<=T;cas++){
            scanf("%d",&n);
            getMatrix();
            int r = (n-Rank(P,n));
            LL ans = 1;
            for (;r--;)ans=(ans<<1)%MOD;
            ans = (ans + MOD - 1) % MOD;
            printf("Case #%d:
    %I64d
    ", cas, ans);
        }
        return 0;
    }

    比赛当场用的高斯消元的板

    LL Gauss(LL a[][N], const LL& n) {
        LL res = 0, r = 0;
        for (LL i = 0; i < n; i++) {
            for(LL j = r; j <= P; j++) {
                if (a[j][i] != 0) {
                    for (LL k = i; k < n; ++k)
                        swap(a[j][k], a[r][k]);
                    break;
                }
            }
            if (a[r][i] == 0) {++res;continue;}
            for (LL j = 0; j <= P; j++) {
                if (j != r && a[j][i] != 0) {
                    LL tmp = a[j][i] / a[r][i];
                    for (LL k = i; k < n; k++) {
                        a[j][k] -= tmp * a[r][k];
                    }
                }
            }
            ++r;
        }
        return res;
    }
    

    后续会补一点高斯消元的简单题在这里

    hdu3364
    这次换了WY给的板
    本题消元方式还是比较简单的,直接异或就行了

    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<iostream>
    #include<vector>
    using namespace std;
    typedef long long LL;
    const double EPS=1e-6;
    const int N=55;
    
    struct matrix{
        int a[N][N];
        int row,col;
        matrix():row(N),col(N){memset(a,0,sizeof(a));}
        matrix(int x,int y):row(x),col(y){
            memset(a,0,sizeof(a));
        }
        int* operator [](int x){return a[x];}
        void print(){
            for (int i=0;i<row;i++){
                for (int j=0;j<col;j++)
                    printf("%d ",a[i][j]);
                puts("");
            }
            puts("");
        }
    };
    
    int Gauss(matrix a,int m,int n){
        int x_cnt = 0;
        int col, k;         //col为列号,k为行号
        for (k=0,col=0;k<m&&col<n; ++k, ++col){
            int r = k;      //r为第col列的一个1
            for (int i=k;i<m;++i) if (a[i][col])r=i;
            if (!a[r][col]){ k--; continue;}
            if (r!=k)for (int i=col;i<=n;++i)
                swap( a[r][i], a[k][i]);
            for (int i=k+1;i<m; ++i)if (a[i][col])//消元
                for (int j=col;j<=n;++j)a[i][j]^=a[k][j];
        }
        for (int i=k;i<m;++i) if (a[i][n])return -1;
        if (k<=n)return n-k;     //返回自由元个数
    }
    
    int main(){
        //freopen("fuck.in","r",stdin);
        int T,n,m,k,x,q;
        scanf("%d", &T);
        for (int cas=1;cas<=T;cas++){
            printf("Case %d:
    ",cas);
            scanf("%d%d",&n,&m);
            matrix mat(n,m+1);
            for (int i=0;i<m;i++){
                scanf("%d",&k);
                for (;k--;){
                    scanf("%d",&x);
                    mat[x-1][i] = 1;
                }
            }
            for (scanf("%d",&q);q--;){
                matrix a = mat;
                for (int i=0;i<n;i++){
                    scanf("%d",&x);
                    if (x)a[i][m]=1;
                }
                int k = Gauss(a,n,m);
                if (k==-1)puts("0");
                else printf("%I64d
    ",1LL<<k);
            }
        }
        return 0;
    }
    

    hilocoder1195,这个是少有的裸题,
    http://hihocoder.com/problemset/problem/1195?sid=853427

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    using namespace std;
    const int N = 1010;
    const double EPS=1e-7;
    int m,n;
    double a[N][N],x[N];
    
    void print(){
        for (int i=0;i<m;i++){
            for (int j=0;j<=n;j++)
                printf("%d ",a[i][j]);
            puts("");
        }
        puts("");
    }
    
    int Gauss(int m,int n){
        int col=0, k=0;//col为列号,k为行号
        for (;k<m&&col<n;++k,++col){
            int r = k;
            for (int i=k+1;i<m;++i)
                if(fabs(a[i][col])>fabs(a[r][col]))r=i;
            if (fabs(a[r][col])<EPS){k--;continue;}//列全为0
            if (r!=k)for(int i=col;i<=n;++i)
                swap(a[k][i],a[r][i]);
            for (int i=k+1;i<m;++i)//消元
                if(fabs(a[i][col])>EPS){
                double t = a[i][col]/a[k][col];
                for (int j=col;j<=n;j++)a[i][j]-=a[k][j]*t;
                a[i][col] = 0;
            }
        }
        for(int i=k ;i<m ;++i)//无解
            if (fabs(a[i][n])>EPS) return -1;
        if (k < n) return n - k;  //自由元个数
        for (int i =n-1; i>=0; i--){//回带求解
            double temp = a[i][n];
            for (int j=i+1; j<n; ++j)
                temp -= x[j] * a[i][j];
            x[i] = (temp / a[i][i]);
        }
        return 0;
    }
    
    int main(){
        //freopen("fuck.in","r",stdin);
        for (;~scanf("%d%d",&n,&m);){
            for (int i=0;i<m;i++)
                for(int j=0;j<=n;j++)scanf("%lf",&a[i][j]);
            int k = Gauss(m,n);
            if (k<0) puts("No solutions");
            else if (k>0) puts("Many solutions");
            else for (int i=0;i<n;i++)
                printf("%d
    ",(int)(x[i]+0.5));
        }
        return 0;
    }
    
  • 相关阅读:
    NOI Online 2020「Prelude」
    CF704E Iron Man
    luogu P4619 [SDOI2018]旧试题
    luogu P4207 [NOI2005]月下柠檬树
    JOI2020
    luogu P3263 [JLOI2015]有意义的字符串
    p1864
    p1824
    p1836
    p1862
  • 原文地址:https://www.cnblogs.com/cww97/p/12349388.html
Copyright © 2011-2022 走看看