【枚举】【最小表示法】XVII Open Cup named after E.V. Pankratiev Stage 14, Grand Prix of Tatarstan, Sunday, April 2, 2017 Problem F. Matrix Game

给你一个n*m的字符矩阵,将横向(或纵向)全部裂开,然后以任意顺序首尾相接,然后再从中间任意位置切开,问你能构成的字典序最大的字符串。

以横向切开为例,纵向类似。

将所有横排从大到小排序,枚举最后切开的位置在哪一横排,将这一排提到排序后的字符串数组最前面,求个“最大表示法”,如果最大表示法的位置恰好在第一排的位置,那么可以用来更新答案。

如果不在第一排的位置,那么其所构成的仍然是合法的串,而且一定不会影响答案。

这是一个最小表示法的板子。

#include<cstdio>
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
string a[105],ans,b[105];
int n,m;
bool cmp(const string &a,const string &b){
	return a>b;
}
int MaxRep(string s, int l)    
{    
    int i,j,k;  
    i=0;j=1;k=0;  
    while(i<l&&j<l)  
    {  
        k=0;  
        while(s[i+k]==s[j+k]&&k<l) k++;  
        if(k==l) return i;  
        if(s[i+k]<s[j+k])   //¸Ä³É´óÓÚ¾ÍÊÇ×îС±íʾ
         if(i+k+1>j) i=i+k+1;  
         else i=j+1;  
        else if(j+k+1>i) j=j+k+1;  
        else  j=i+1;   
    }  
    if(i<l) return i;  
    else return j;  
}  
int main(){
//	freopen("f.in","r",stdin);
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;++i){
		cin>>a[i];
	}
	for(int i=0;i<n;++i){
		for(int j=0;j<m;++j){
			b[j]+=a[i][j];
		}
	}
	sort(a,a+n,cmp);
	for(int i=0;i<n;++i){
		string t=a[i];
		for(int j=0;j<n;++j){
			if(j!=i){
				t+=a[j];
			}
		}
//		cout<<i<<": "<<t<<' ';
		int p=MaxRep(t,n*m);
		string pre=t.substr(0,p);
		t.erase(0,p);
		t+=pre;
//		cout<<t<<endl;
		ans=max(ans,t);
	}
	sort(b,b+m,cmp);
	for(int i=0;i<m;++i){
		string t=b[i];
		for(int j=0;j<m;++j){
			if(j!=i){
				t+=b[j];
			}
		}
//		cout<<i<<": "<<t<<' ';
		int p=MaxRep(t,n*m);
		string pre=t.substr(0,p);
		t.erase(0,p);
		t+=pre;
//		cout<<t<<endl;
		ans=max(ans,t);
	}
	for(int i=0;i<n*m;++i){
		if(i!='0'){
			for(int j=i;j<n*m;++j){
				putchar(ans[j]);
			}
			puts("");
			return 0;
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/autsky-jadek/p/7287013.html