noip 2012 国王游戏

考虑交换相邻两个二元组的影响,交换i和i+1,实际上只影响到Fi和Fi+1。

设T A1 A2 ... Ai-2 Ai-1

方案A:Fi Bi,Fi+1 =T Ai Bi+1

方案B:Fi Bi+1,Fi+1 =T Ai+1 Bi

假设1 Bi < Ai Bi+1,1 Bi+1 < Ai+1 Bi

那么方案A优于方案B  <=>  Ai Bi+1 < Ai+1 Bi  <=>  Ai Bi < Ai+1 i+1

假设1 Bi ≥ Ai Bi+1  =>  Ai Bi ≤ Bi+1

那么1 Bi ≤ Ai+1 Bi,方案A更优

假设1 Bi+1 ≥ Ai+1 Bi  =>  Ai+1 Bi+1 ≤ Bi

那么1 Bi+1 ≤ Ai Bi+1,方案B更优

也就是说,对于相邻两个二元组,将A B的较小的放在前面总能使答案更优。

已经按A B排好序的方案为{1,2,3,4,...n},发现可以通过一种构造,生成所有其他排列且保证结果更差。

假 设任意一种排列是{P1,P2,P3,P4....Pn},称为目标序列。{1,2,3,4,...n},称为原始序列。我们观察目标序列,从后往前,每 次将Pi从原始序列中往后交换直到它位于目标序列的位置。不难发现,序列在任意时刻都是由单调增的一段和排列好的一段组成,且每次交换都能保证结果更差。

综上,最优方案就是按A B递增排序的方案,具体实现的时候需要加高精度处理

#include"stdio.h"
#include"limits.h"
#include"stdlib.h"
#include"string.h"
int left[1001],right[1001],m_len=0,a_len,b_len;
int b[10000],e,d,n,ans[10000],max[10000];       
struct stu{
       int left,right;
       int sum;
       };       
  struct stu a[1001];
int cmp(const void*_a,const void*_b)
   {   stu *a=(stu*)_a;
       stu *b=(stu*)_b;
       return a->sum-b->sum; }

int div(int m){   
     int i,j,x,temp=0; 
    memset(ans,0,sizeof(ans));
     a_len=0;
      x=a[m].right;
     for(j=b_len-1;j>=0;j--)
      { temp=temp*10;
         temp+=b[j];
       if(temp>x)break;      } 
         ans[a_len]=temp/x;
       temp=temp%x;
       a_len++;
    for(i=j-1;i>=0;i--)
       {   temp=temp*10;
         temp+=b[i];
         ans[a_len]=temp/x;
          temp=temp%x;
          a_len++;} 
       }
int my_cmp()
{   int i,j,result=0;
    if(a_len>m_len)result=1;
 else {
      for(i=0;i<a_len;i++)
        { if(ans[i]>max[i]){result=1;break;}
      else if(ans[i]<max[i]){result=0;break;}
}
      }
  if(result==1)
   {  memset(max,0,sizeof(max));
       for(i=0;i<a_len;i++) 
       max[i]=ans[i]; 
       m_len=a_len;       
           }      
        return 0;            
    }
int cacu(int m)
{    int i,j;
    j=a[m].left;
  for(i=0;i<b_len;i++)
         b[i]*=j;
    for(i=0;i<b_len;i++)
    {   if(b[i]>=10&&i<b_len-1)
            {  b[i+1]+=b[i]/10;
            b[i]=b[i]%10;
            }            
        else  if(b[i]>=10&&i==b_len-1)
            {  b[i+1]+=b[i]/10;
            b[i]=b[i]%10;
            b_len++;
  
            }               
                          }               
                          }
main()
{   int i,j;
   freopen("in.txt","r",stdin);
   freopen("out.txt","w",stdout);
    scanf("%d",&n);
      scanf("%d%d",&d,&e);
      memset(a,0,sizeof(a));
      memset(ans,0,sizeof(ans));
      memset(max,0,sizeof(max));
    for(i=0;i<n;i++)
      {scanf("%d%d",&a[i].left,&a[i].right);
           a[i].sum=a[i].left*a[i].right; }
     qsort(a,n,sizeof(a[0]),cmp);
      b[0]=d;b_len=1; 
      
      for(i=0;i<n;i++)
   {   div(i);
        my_cmp();
       cacu(i); }
   for(i=0;i<m_len;i++)
        printf("%d",max[i]);
                 
                                
      }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值