题意:有n个‘o’,m个‘x’可以任意地排成一排,每连续的a个‘o’,ans就加上a*a,每连读的b个‘x’,ans就减掉b*b,问ans最大可以为多少,并输出此时的一种排列方式;
解法:根据数的性质可以知道,为使ans最大,应尽量是‘o’聚集在一起,'x'分隔开来。结果就是n个‘o’中分离出k个(k段的‘o’,和一段的‘oo...o’(长度n-k)),此时把m个‘x’尽量平均分成了k+2段。解的结构应该是这样,关键是找到使得答案最优的k,我发现k对于ans有离散单峰的性质,但是比赛时候老是调不出结果,以前写的三分都是连续化的。后来问了爱神才知道针对这种情况是不能三分的,其实枚举就行了,n和m最大100000,每次计算都是O(1),只能说比赛时又逗了。
/****************************************************
* author:xiefubao
*******************************************************/
#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <stack>
#include <string.h>
using namespace std;
#define eps 1e-8
typedef long long LL;
long long a,b;
LL make(int k)
{
if(k<0) return -10000000000000;
LL tool1=k+(a-k)*(a-k);
LL tool2=(b/(k+2))*(b/(k+2))*(k+2-b%(k+2));
tool2+=(b/(k+2)+1)*(b/(k+2)+1)*(b%(k+2));
return tool1-tool2;
}
int main()
{
cin>>a>>b;
if(b==0||b==1)
{
cout<<a*a-b*b<<endl;
for(int i=0;i<a;i++) cout<<"o";
for(int i=0;i<b;i++)cout<<"x";
}
else if(a==0)
{
cout<<-b*b<<endl;
for(int i=0;i<b;i++)cout<<'x';
}
else
{
int to=0;
LL ans=make(0);
for(int i=1;i<=min(a-1,b-2);i++)
{
if(make(i)>ans)
{
ans=make(i);to=i;
}
}
int right=to;
cout<<make(right)<<endl;
int k=right;k+=1;
for(int i=0;i<b/(k+1);i++) cout<<'x';
for(int i=0;i<min((LL)k-1,k+1-b%(k+1)-1);i++)
{
cout<<"o"; for(int j=0;j<b/(k+1);j++) cout<<'x';
}
for(int i=1;i<b%(k+1);i++)
{
cout<<"o"; for(int j=0;j<b/(k+1)+1;j++) cout<<'x';
}
for(int i=0;i<a-k+1;i++)cout<<'o';for(int j=0;j<b/(k+1);j++) cout<<'x';
if(b%(k+1)!=0) cout<<"x"<<endl;
}
return 0;
}
代码: