关于高维卷积的一些不成熟的想法

\(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

posted @ 2019-04-09 07:25  Yuhuger  阅读(408)  评论(0编辑  收藏  举报