关于高维卷积的一些不成熟的想法
设\(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