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;
    }
    
  • 相关阅读:
    hdu5728 PowMod
    CF1156E Special Segments of Permutation
    CF1182E Product Oriented Recurrence
    CF1082E Increasing Frequency
    CF623B Array GCD
    CF1168B Good Triple
    CF1175E Minimal Segment Cover
    php 正则
    windows 下安装composer
    windows apache "The requested operation has failed" 启动失败
  • 原文地址:https://www.cnblogs.com/cww97/p/7533981.html
Copyright © 2011-2022 走看看