题目大意:给定n,m,n为奇数,求一个m行n列的矩阵,满足每一列是一个1到m的排列,且每一行相邻两数差的绝对值不超过1,使得和最大的一行的和尽量小。
题解:果断爆搜打表找规律,加了一个最优性剪枝轻松跑出m=7。
对着表看就很显然了,表附在代码后面。
#include<bits/stdc++.h>
#define gc getchar()
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
const int N=100;int ans,p[N][N];
inline int gabs(int x) { return x<0?-x:x; }
inline int calc(int n,int m)
{
int qwq=0;
rep(i,1,m)
{
int s=0;
rep(j,1,n) s+=p[j][i];
qwq=max(qwq,s);
}
return qwq;
}
inline int min_max_line(int x,int n,int m)
{
int qwq=0;
rep(i,1,m)
{
int s=0;
rep(j,1,x) s+=p[j][i];
for(int j=x+1,t=p[x][i]-1;j<=n;j++,t--)
t=max(1,t),s+=t;
qwq=max(qwq,s);
}
return qwq;
}
int dfs(int x,int n,int m)
{
if(x==n+1) return ans=min(ans,calc(n,m));
if(min_max_line(x-1,n,m)>=ans) return 0;
rep(i,1,m) p[x][i]=i;
do{
int ok=1;
rep(i,1,m) if(gabs(p[x][i]-p[x-1][i])>1) { ok=0;break; }
if(ok) dfs(x+1,n,m);
}while(next_permutation(p[x]+1,p[x]+m+1));
return 0;
}
#ifdef ONLINE_JUDGE
namespace IO { const int S=(1<<20)+5;char buf[S],*H,*T;inline char getc() { if(H==T) T=(H=buf)+fread(buf,1,S,stdin);if(H==T) return -1;return *H++; }
inline int inn() { int x=0,c=getc();while(!isdigit(c)) c=getc();while(isdigit(c)) x=(((x<<2)+x)<<1)+(c^'0'),c=getc();return x; } }using namespace IO;
#else
inline int inn() { int x,ch;while((ch=gc)<'0'||ch>'9');x=ch^'0';while((ch=gc)>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^'0');return x; }
#endif
char ss[20000000],tt[20];int ssl,ttl;
inline int show(int x)
{
if(!x) ss[++ssl]='0';
for(ttl=0;x;x/=10) tt[++ttl]=char(x%10+'0');
for(;ttl;ttl--) ss[++ssl]=tt[ttl];
return ss[++ssl]='\n';
}
int main()
{
#ifdef DA_BIAO
freopen("biao.txt","w",stdout);
printf("f( m, n) = ans\n");
for(int m=2;m<=7;m++)
{
for(int n=3;n<2*m;n+=2)
{
assert(n>=3&&n%2==1&&n<m*2&&m>=2);
rep(i,1,m) p[1][i]=i;
ans=n*m,dfs(2,n,m);
printf("f( %d, %2d) =%3d ",m,n,ans);
}
printf("\n");
}
return 0;
#endif
for(int T=inn();T;T--)
{
int m=inn(),n=inn();
show(3*m-1+2*m*(n-3)/2-(n+1)*(n-3)/4);
}
return fwrite(ss+1,sizeof(char),ssl,stdout),0;
}
/*biao.txt for 2 <= m <= 7
f( m, n) = ans
f( 2, 3) = 5
f( 3, 3) = 8 f( 3, 5) = 11
f( 4, 3) = 11 f( 4, 5) = 16 f( 4, 7) = 19
f( 5, 3) = 14 f( 5, 5) = 21 f( 5, 7) = 26 f( 5, 9) = 29
f( 6, 3) = 17 f( 6, 5) = 26 f( 6, 7) = 33 f( 6, 9) = 38 f( 6, 11) = 41
f( 7, 3) = 20 f( 7, 5) = 31 f( 7, 7) = 40 f( 7, 9) = 47 f( 7, 11) = 52 f( 7, 13) = 55 */
//conclusion : f(m,n)=f(m-1,n)+n
//conclusion : f(m,n)+(2m-n)=f(m,n+2)
//conclusion : f(m,3)=3m-1
/*conclusion :
f(m,n)=f(m,3)+(2m-3)+(2m-5)+...+(2m-(n-2))
f(m,n)=f(m,3)+2m*(n-3)/2-(3+5+..+(n-2))
f(m,n)=f(m,3)+2m*(n-3)/2-(n+1)(n-3)/2/2
f(m,n)=3m-1+2m(n-3)/2-(n+1)(n-3)/4
*/