zoukankan      html  css  js  c++  java
  • p进制线性基填坑

    问题:输入(m)(n)(p)进制数,定义加法和乘法都是模(p)意义下不进位加法乘法运算,求这些数线性组合能得到的最大(p)进制数(一般意义上)
    代码:

    #include <iostream>
    const int N=110;
    int n,p;
    struct num{
        int bits[N];
        num(){
            for (int i=0; i<n; ++i) bits[i]=0;
        }
        bool operator !()const{
            for (int i=0; i<n; ++i) if (bits[i]) return 0;
            return 1;
        }
        num operator *(const int &u){
            num ret=*this;
            for (int i=0; i<n; ++i)
                ret.bits[i]=ret.bits[i]*u%p;
            return ret;
        }
        num operator -(const num &u){
            num ret=*this;
            for (int i=0; i<n; ++i){
                ret.bits[i]-=u.bits[i];
                if (ret.bits[i]<0) ret.bits[i]+=p;
            }
            return ret;
        }
        num operator +(const num &u){
            num ret=*this;
            for (int i=0; i<n; ++i){
                ret.bits[i]+=u.bits[i];
                if (ret.bits[i]>=p) ret.bits[i]-=p;
            }
            return ret;
        }
        friend std::ostream & operator <<(std::ostream & os,const num &_){
            for (int i=0; i<n; ++i)
                os<<_.bits[i]<<" ";
            return os;
        }
    }base[N],a;
    void exgcd(int &x,int &y,int a,int b)
    {
        if(!b)
        {
            x=1;
            y=0;
            return;
        }
        exgcd(x,y,b,a%b);
        int t=x;
        x=y;
        y=t-a/b*y;
    }
    void insert(num a){
        for (int i=0; i<n; ++i) {
            if (!base[i]) {
                int xx, yy;
                exgcd(xx, yy, a.bits[i], p);
                xx=(xx%p+p)%p;
                base[i] = a*xx;
                break;
            }
            else if (a.bits[i]%base[i].bits[i]==0){
                int tmp=a.bits[i]/base[i].bits[i];
                a=a-base[i]*tmp;
            }
            else{
                int xx,yy;
                exgcd(xx,yy,a.bits[i],base[i].bits[i]);
                xx=(xx%p+p)%p;
                yy=(yy%p+p)%p;
                base[i]=a*xx+base[i]*yy;
                break;
            }
        }
    }
    num max_value(){
        num ret;
        for (int i=0; i<n; ++i)
        if (base[i].bits[i]){
            for (int j=p-1; j>=0; --j)
                if ((j-ret.bits[i])%base[i].bits[i]==0) {
                    ret=ret+base[i]*((j-ret.bits[i])/base[i].bits[i]);
                    break;
                }
        }
        return ret;
    }
    int m;
    int main() {
        scanf("%d%d",&n,&p);
        scanf("%d",&m);
        for (int i=1; i<=m; ++i){
            for (int j=0; j<n; ++j)
            scanf("%d",&a.bits[j]);
            insert(a);
            for (int i=0; i<n; ++i){
                std::cerr<<base[i];
                std::cerr<<std::endl;
            }
            std::cerr<<"insertend"<<std::endl;
        }
        std::cout<<max_value();
        return 0;
    }
    

    这个代码也不知道对不对,可能只有p是质数的时候是对的。但是是我之前想法的实现。

         struct num{
              int bits[N];
          }
    

    代表一个p进制数,bits[0]表示最高位。

    base[N]是一个线性基
    其中base[i]是一个p进制数,表示第i位的基为base[i]

    insert(a)的时候从高位往低位扫
    假设扫到第i位,分三种情况讨论
    Case 1:该位的基还不存在
    考虑在二进制的线性基中我们是怎么做的,我们直接将基赋值成当前元素。
    但是在p进制中,这一位可以表示的值是(gcd(p,a[i]))的倍数,那么就需要将当前的(a)乘以若干倍之后作为基。
    Case 2:基存在,且基可以表示a的第i位
    那么仿效二进制的情况,将a的第i位变成0,继续做
    Case 3:基存在,且基不能表示a的第i位
    那么加入了当前元素之后这一位可以表示的值是(gcd(base[i][i],a[i]))的倍数,我们修改一下基,使基的第i位变为gcd
    修改基时需要解(ax+by=gcd(a,b)),可以使用扩展欧几里德算法。

    最后算最大值的时候就按位贪心即可,我实现得暴力了一些。
    由于我也不是很确定算法的正确性,欢迎来Hack。

    Upd:上面那份代码是有锅的,insert的时候可能需要分四类讨论,还有一类是a的第i位可以表示基,那么交换一下基和a。
    新的不知道是对还是错的代码

    #include <iostream>
    const int N=110;
    int n,p;
    struct num{
        int bits[N];
        num(){
            for (int i=0; i<n; ++i) bits[i]=0;
        }
        bool operator !()const{
            for (int i=0; i<n; ++i) if (bits[i]) return 0;
            return 1;
        }
        num operator *(const int &u){
            num ret=*this;
            for (int i=0; i<n; ++i)
                ret.bits[i]=ret.bits[i]*u%p;
            return ret;
        }
        num operator -(const num &u){
            num ret=*this;
            for (int i=0; i<n; ++i){
                ret.bits[i]-=u.bits[i];
                if (ret.bits[i]<0) ret.bits[i]+=p;
            }
            return ret;
        }
        num operator +(const num &u){
            num ret=*this;
            for (int i=0; i<n; ++i){
                ret.bits[i]+=u.bits[i];
                if (ret.bits[i]>=p) ret.bits[i]-=p;
            }
            return ret;
        }
        friend std::ostream & operator <<(std::ostream & os,const num &_){
            for (int i=0; i<n; ++i)
                os<<_.bits[i]<<" ";
            return os;
        }
    }base[N],a;
    void exgcd(int &x,int &y,int a,int b)
    {
        if(!b)
        {
            x=1;
            y=0;
            return;
        }
        exgcd(x,y,b,a%b);
        int t=x;
        x=y;
        y=t-a/b*y;
    }
    void insert(num a){
        for (int i=0; i<n; ++i) {
        	if (!a) break;
            if (!base[i]) {
                int xx, yy;
                exgcd(xx, yy, a.bits[i], p);
                xx=(xx%p+p)%p;
                base[i] = a*xx;
            }
            else if (a.bits[i]%base[i].bits[i]==0);
            else if (base[i].bits[i]%a.bits[i]==0) std::swap(a,base[i]);
            else{
                int xx,yy;
                exgcd(xx,yy,a.bits[i],base[i].bits[i]);
                xx=(xx%p+p)%p;
                yy=(yy%p+p)%p;
                base[i]=a*xx+base[i]*yy; 
            }
            int tmp=a.bits[i]/base[i].bits[i];
            a=a-base[i]*tmp;
        }
    }
    num max_value(){
        num ret;
        for (int i=0; i<n; ++i)
        if (base[i].bits[i]){
            for (int j=p-1; j>=0; --j)
                if ((j-ret.bits[i])%base[i].bits[i]==0) {
                    ret=ret+base[i]*((j-ret.bits[i])/base[i].bits[i]);
                    break;
                }
        }
        return ret;
    }
    int m;
    int main() {
        scanf("%d%d",&n,&p);
        scanf("%d",&m);
        for (int i=1; i<=m; ++i){
            for (int j=0; j<n; ++j)
            scanf("%d",&a.bits[j]);
            insert(a);
            for (int i=0; i<n; ++i){
                std::cerr<<base[i];
                std::cerr<<std::endl;
            }
            std::cerr<<"insertend"<<std::endl;
        }
        std::cout<<max_value();
        return 0;
    }
    }
    
  • 相关阅读:
    python实现二分查找算法例子代码
    Python实现计算圆周率π的值到任意位的方法示例
    什么是TWS耳机
    [置顶] 单例模式lua实现
    推荐五星级C语言学习网站
    poj2689 Prime Distance 有难度 埃拉托斯尼斯筛法的运用
    局域网
    pager-taglib分页处理的使用
    创建ListView的基本步骤
    求最大连续子数列和(只扫描一次数列)
  • 原文地址:https://www.cnblogs.com/Yuhuger/p/14320193.html
Copyright © 2011-2022 走看看