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;
}
}
posted @ 2021-01-24 10:32  Yuhuger  阅读(118)  评论(0编辑  收藏  举报