zoukankan      html  css  js  c++  java
  • 关于高维卷积的一些不成熟的想法

    (K)为进制,(d)为位数。
    (n=K^d)
    这里认为(K << n)

    假设现在给出(K*K)的矩阵,需要做任意高维卷积。

    那么考虑直接分治乘,算法显然是(n^2)的。

    考虑在支持减法的情况下,可以用全集减其他算出某一维,时间复杂度为
    (T(n)=(K^2-K+1)T(n/K)+O(n))
    然而我并不会解这个递归式,当(K=2)时,复杂度好像是(O(n^{1.59}))

    设计容斥也可以,但是较高的进制设计容斥比较困难。

    那么剩下的问题的一种解决方法是,每次你可选一个行的集合,一个列的集合,你要让选的次数最少的情况下,可以线性组合出(K)个长度为(K^2)(0,1)向量,并且这些向量两两不交,并是全集。
    模拟退火大法好。
    当然剩下的问题是这种解决方法的超集,也就是说,这种方法的最优解可能是可以被改进的。

    一份用人类智慧的代码。

    #pragma GCC optimize(3)
    #pragma GCC optimize("Ofast")
    #pragma GCC optimize("inline")
    #include <iostream>
    #include <stdio.h>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    typedef std::vector<int> vi;
    std::ostream& operator <<(std::ostream &os,const vi &v){
        for (auto i:v) os<<i<<" ";
        return os;
    }
    template<size_t K>
    struct solver{
        static const int D=18;
        int mx,trans[K][K],pwd[D];
        bool vis[K][K];
        std::vector<std::pair<int,int> > g[K];
        void solve(int d,int *a,int *b,int *y){
            //cerr<<"solve"<<d<<"|"<<a<<"|"<<b<<"YYYY"<<y<<endl;
            if (d==1){
                //cerr<<"????"<<endl;
                //for (int i=0; i<k; ++i) y[i]=0;
                for (int i=0; i<K; ++i)
                    if (a[i]){
                        //cerr<<"FC"<<i<<endl;
                        int *g=trans[i],*h=b;
                        for (int j=0; j<K; ++j){
                            //cerr<<"JJJ"<<j<<" "<<(*g)<<endl;
                            y[*(g++)]^=(*h++);
                            //cerr<<"BBB"<<endl;
                        }
                    }
                //cerr<<"DY"<<y<<endl;
                return;
            }
          
            vi av(pwd[d-1]),bv(pwd[d-1]),yv(pwd[d-1]),zv(pwd[d-1]);
            int *aa=av.data(),*bb=bv.data(),*yy=yv.data(),*zz=zv.data();
            for (int i=0,z=0; i<pwd[d]; ++i,z=(z+1==pwd[d-1]?0:z+1))
                aa[z]^=a[i];
            for (int i=0,z=0; i<pwd[d]; ++i,z=(z+1==pwd[d-1]?0:z+1))
                bb[z]^=b[i];
            solve(d-1,aa,bb,yy);
      
            for (int i=0; i<K; ++i){
                if (i==mx) continue;
                //cerr<<"SL"<<i<<endl;
                for (int j=0; j<pwd[d-1]; ++j) zz[j]=0;
                for (auto j:g[i]){
                    if (j.first<K){
                        int tmp=j.first;
                        memset(bb,0,pwd[d-1]*sizeof(*bb));
                        /*for (int i=0; i<pwd[d-1]; ++i)
                          aa[i]=a[tmp*pwd[d-1]+i];*/
                        memcpy(aa,a+tmp*pwd[d-1],pwd[d-1]*sizeof(*aa));
                        for (int x=j.second; x; x&=x-1){
                            int *g=bb,*h=b+__builtin_ctz(x)*pwd[d-1];
                            for (int i=0; i<pwd[d-1]; ++i)
                                (*(g++))^=*(h++);
                        }
                    }
                    else{
                        int tmp=j.first-K;
                        //for (int i=0; i<pwd[d-1]; ++i) aa[i]=0;
                        memset(aa,0,pwd[d-1]*sizeof(*aa));
                        memcpy(bb,b+tmp*pwd[d-1],pwd[d-1]*sizeof(*bb));
                        for (int x=j.second; x; x&=x-1){
                            int *g=aa,*h=a+__builtin_ctz(x)*pwd[d-1];
                            for (int i=0; i<pwd[d-1]; ++i)
                                (*(g++))^=*(h++);
                        }
                    }
                    solve(d-1,aa,bb,zz);
                    //cerr<<"OIT"<<d<<endl;
                }
                int *g=y+i*pwd[d-1],*h=zz;
                for (int j=0; j<pwd[d-1]; ++j) (*(g++))^=*(h++);//care
                for (int j=0; j<pwd[d-1]; ++j) yy[j]^=zz[j];
            }
            int *g=y+mx*pwd[d-1],*h=yy;
            for (int i=0; i<pwd[d-1]; ++i) (*(g++))^=*(h++);//care
            //cerr<<"ED"<<d<<endl;
        }
        void dodo(int d){
            pwd[0]=1;
            for (int i=1; i<=d; ++i) pwd[i]=pwd[i-1]*K;
            for (int i=0; i<K; ++i)
                for (int j=0; j<K; ++j){
                    scanf("%d",&trans[i][j]);
                }
         
            for (int i=0; i<K; ++i){
                int now=(1<<K)-1;
                for (int j=0; j<(1<<(K<<1)); ++j){
                    bool fl=1;
                    for (int h=0; h<K; ++h)
                        if (!(j>>h&1))
                            for (int l=0; l<K; ++l)
                                if (!(j>>(l+K)&1)){
                                    if (trans[h][l]==i) fl=0;
                                    //cerr<<"deltype"<<j<<" "<<h<<" "<<l<<endl;
                                }
                    if (fl){
                        if (__builtin_popcount(j)<__builtin_popcount(now)) now=j;
                    }
                }
                //cerr<<"now"<<now<<endl;
                for (int x=now; x; x&=x-1){
                    int t=__builtin_ctz(x),bb=0;
                    if (t<K){
                        for (int l=0; l<K; ++l)
                            if (trans[t][l]==i&&!vis[t][l]){
                                bb|=1<<l;
                                trans[t][l]=i;
                                vis[t][l]=1;
                            }
                    }
                    else{
                        for (int h=0; h<K; ++h)
                            if (trans[h][t-K]==i&&!vis[h][t-K]){
                                bb|=1<<h;
                                vis[h][t-K]=1;
                            }
                    }
                    //cerr<<i<<" "<<t<<" "<<bb<<endl;
                    g[i].push_back({t,bb});
                }
            }
            for (int i=1; i<K; ++i)
                if (g[i].size()>g[mx].size())
                    mx=i;
            //cerr<<"mx"<<mx<<endl;
            vi alpha(pwd[d]),beta(pwd[d]),rec(pwd[d]);
            for (int i=0; i<pwd[d]; ++i){
                scanf("%d",&alpha[i]);
                alpha[i]%=2;
            }
            for (int i=0; i<pwd[d]; ++i){
                scanf("%d",&beta[i]);
                beta[i]%=2;
            }
            solve(d,alpha.data(),beta.data(),rec.data());
            //cerr<<"?????"<<endl;
            std::cout<<rec;
        }
    };
    solver<2> solver2;
    solver<3> solver3;
    solver<4> solver4;
    solver<5> solver5;
    int main(){
        int d,k;
        scanf("%d%d",&d,&k);
        switch (k){
        case 2:solver2.dodo(d); break;
        case 3:solver3.dodo(d); break;
        case 4:solver4.dodo(d); break;
        case 5:solver5.dodo(d); break;   
        }
        return 0;
    }
    

    考虑继续用人类智慧优化,
    考虑分治策略,把一个矩阵拆成四个矩阵计算,可以得到的递归子问题数量如程序输出。

    #include <bits/stdc++.h>
    using namespace std;
    int f[61][61][3610];
    int main(){
    	for (int i=1; i<=60; ++i) 
    		for (int j=1; j<=60; ++j) f[i][j][1]=1;
    	for (int i=1; i<=60; ++i)
    		for (int j=1; j<=60; ++j){
    			int mid1=i/2;
    			int mid2=j/2;
    			for (int k=2; k<=i*j; ++k){
    				f[i][j][k]+=f[mid1][mid2][min(mid1*mid2,k)];
    				f[i][j][k]+=f[mid1][j-mid2][min(mid1*(j-mid2),k)];
    				f[i][j][k]+=f[i-mid1][mid2][min((i-mid1)*mid2,k)];
    				f[i][j][k]+=f[i-mid1][j-mid2][min((i-mid1)*(j-mid2),k)];
    				f[i][j][k]=min(f[i][j][k],(min(i*j,k)-1)*min(i,j)+1);
    			}
    		}
    	for (int i=2; i<=60; ++i) cout<<i<<" "<<f[i][i][i]<<endl;
    }
    

    但是这样还是没有变优,gg

  • 相关阅读:
    Django笔记:上下文处理器和中间件
    Django笔记:Cookie和Session
    redhat 7.4从openssh7.6离线升级openssh8.4p1解决方法
    “应用程序无法正常启动(0xc000007)”处理办法
    "安装VMware Tools"显示灰色的解决办法
    redis 根据模板批量生成使用不同端口的配置文件并运行运行服务
    扩展 docker 管理命令
    shell getopt 讲解
    编写 Redis 测试 shell 脚本
    自定义 shell 软件安装脚本
  • 原文地址:https://www.cnblogs.com/Yuhuger/p/10674682.html
Copyright © 2011-2022 走看看