cf(cards)数学题

题意:有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;
}

代码:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值