dcx矩阵 - 打表 - 找规律

题目大意:给定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
*/

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/83586325