TC SRM 552 DIV2

转载请注明出处,谢谢 http://blog.csdn.net/ACM_cxlove?viewmode=contents           by---cxlove

悲剧的一场,断网加手贱。。。

250PT:FoxAndFlowerShopDivTwo

水题,一个矩形中有一个格子不能取,取出一个子矩阵,包含'F'最多

直接考虑限制格子的4个方向,暴力

#include<iostream>
#include<cstdio>
#include<cstring>
class FoxAndFlowerShopDivTwo{
public:
    int theMaxFlowers(vector <string> flowers, int r, int c){
        int ans=0;
        int R=flowers.size();
        int C=flowers[0].size();
        int t=0;
        for(int i=0;i<r;i++)
            for(int j=0;j<C;j++)
                if(flowers[i][j]=='F')
                    t++;
        ans=max(t,ans);
        t=0;
        for(int i=r+1;i<R;i++)
            for(int j=0;j<C;j++)
                if(flowers[i][j]=='F')
                    t++;
        ans=max(t,ans);
        t=0;
        for(int i=0;i<R;i++)
            for(int j=0;j<c;j++)
                if(flowers[i][j]=='F')
                    t++;
        ans=max(t,ans);
        t=0;
        for(int i=0;i<R;i++)
            for(int j=c+1;j<C;j++)
                if(flowers[i][j]=='F')
                    t++;
        ans=max(t,ans);
        return ans;
    }
};

500PT:FoxPaintingBalls

有三种颜色的球,堆成高度为N的三角形,相邻的球颜色不能一样,问最多能堆成多少个。

可以 YY出简单的规律,当N%3==0或者N%3==2时,首先每堆球的总和是3的倍数

而且可以发现不管怎么堆,3种颜色的球的数量相同。

那么结果就很简单了,可以计算出每堆需要每种颜色多少个,用最少的判断一下就行了。

接下来就是N%3==1,可以发现主要取决于第一层怎么堆,每一层用的颜色比另外两种颜色要多一个,其它两种颜色一样。

那么就肯定想到用颜色最多去放第一层。局部来说这样是正确的,但是数据范围很大,不可能一步步模拟。

而且一段时间之后,本来颜色最多的就并不是最多了。

先不考虑多出的那一个,那么对于每种颜色就要使用N*(N+1)/6个。那么剩下的部分用作多出来的那一个球。

但是剩下的也许会不够用,我们便把堆数-1,那么剩下的球就会多出来,直到满足为止,不幸的是,比赛的时候这样写了,然后挂在一组数据上,TLE了。

其实可以发现不需要一步步模拟,如果不考虑多出的一个,为ans堆,假设我们需要减去k堆。那么最后必然要满足

leftB+leftR+leftG+k*(N*(N+1)/2-1)>=ans-k,也就是最后有ans-k堆,那么就需要剩下的球至少有ans-k个,直接解出不等式的K就行了。

注释部分为原来暴力的,TLE。

class FoxPaintingBalls{
public:
    long long theMax(long long R, long long G, long long B, int N){
        LL ans=0;
        LL n=N;
        if(n%3!=1)
            return min(B,min(R,G))/((LL)n*(n+1)/6);
        if(R<G) swap(R,G);
        if(R<B) swap(R,B);
        if(G<B) swap(G,B);
        if(n==1)  return B+R+G;
        ans=min(R/(n*(n+1)/6),min(G/((n+1)*n/6),B/(n*(n+1)/6)));
        LL leftR=R-(ans*(n*(n+1)/6));
        LL leftG=G-(ans*(n*(n+1)/6));
        LL leftB=B-(ans*(n*(n+1)/6));
        if(leftB+leftG+leftR>=ans)  return ans;
        return ans-(ans-(leftB+leftG+leftR)+n*(n+1)/2-1)/(n*(n+1)/2);
      /*  while(1){
            ans--;
            leftB+=n*(n+1)/6;
            leftR+=n*(n+1)/6;
            leftG+=n*(n+1)/6;
            if(leftB+leftG+leftR>=ans) return ans;
        }
      */
    }
};

1000PT:maximize

还是要继续YY出规律,首先如果N<K的话,显然第N个位置 要放最大的。其它的由于 要字典序最小,那就按从小到大排。

再考虑如果K为奇数的情况。我们往后推一下

a0,a1,a2……ak-1,a0-a1+a2……+ak-1,a1-a2+a3-a4……+(a0-a1+a2……+ak-1)

那么可以发现第k+1项化简后就是a0,依次类推,第k+2项就是a1

只有N%(k+1)==k时,结果是a0-a1+a2……+ak-1,那么要求这个最大,显然奇数项要取大的,偶数项要取小的。

其余情况便是要求a(N%(k+1))项最大,同N<K情况。

再考虑K为偶数情况同样推一下。

a0,a1,a2,……ak-1,a0-a1+a2-……-ak-1,-a0+2a1-2a2+2a3……+2ak-1,2a0-3a1+4a2……-4ak-1

可以发现后面每项的系数在逐渐递增,首先当N为偶数时,奇数项系数为正,偶数项系数为负,这便要求奇数项为大的,偶数项为小的。再看系数的相对变化,后面项的系数不小于前面的,所以对于大的,后面的要大,而对于小的后面的要小。

但是我们发现在N<2*K时,负数项的系数不完全是严格递增的,也就是后面的系数相同,所以不管顺序怎么样,结果是一样的,而题目要求我们是按字典序,所以要把小的数列,后面的部分递增排序。

最终通过N的奇偶,决定奇数位为大数还是偶数位为大数。

TC的数据弱了,在K为奇数中,如果是N%(K+1)==K的情况下,系数全为+1,-1,所以小的数部分应当也是升序,开始按降序排也过了。。。。囧

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<string>
#include<algorithm>
#include<queue>
#define LL long long
#define eps 1e-7
using namespace std;
bool cmp(int a,int b){
    return a>b;
}
class FoxPlusMinus{
public:
    vector <int> maximize(vector <int> first, int N){
        int k=first.size();
        vector<int>ans,ans1,ans2;
        sort(first.begin(),first.end());
        //N<K的情况,直接把第N位取最大的数
        if(N<k){
            for(int j=0,i=0;j<k;i++,j++)
                if(j==N){
                    ans.push_back(first[k-1]);
                    i--;
                }
                else
                    ans.push_back(first[i]);
            return ans;
        }
        if(k&1){
            //第N%(k+1)项取最大
            if(N%(k+1)!=k){
                N=N%(k+1);
                for(int j=0,i=0;j<k;i++,j++)
                    if(j==N){
                        ans.push_back(first[k-1]);
                        i--;
                    }
                else
                        ans.push_back(first[i]);
                return ans;
            }
            //按奇数位越大越好,偶数位越小越好的原则
            else{
                 for(int i=0,j=k-1;i<k;i+=2,j--)
                     ans1.push_back(first[j]);
                 for(int i=1,j=0;i<k;i+=2,j++)
                     ans2.push_back(first[j]);
                 sort(ans1.begin(),ans1.end());
                 //TC的数据弱下,下面这句排序不能要,因为要保证字典序,应当为升序
           //    sort(ans2.begin(),ans2.end(),cmp);
                 for(int i=0;i<min(ans1.size(),ans2.size());i++){
                     ans.push_back(ans1[i]);
                     ans.push_back(ans2[i]);
                 }
                 if(ans1.size()>ans2.size())
                     ans.push_back(ans1[ans1.size()-1]);
                 return ans;
            }
        }
        else{
            for(int i=0,j=k-1;i<k;i+=2,j--)
                ans1.push_back(first[j]);
            for(int i=1,j=0;i<k;i+=2,j++)
                ans2.push_back(first[j]);
            //大的数从小到大
            sort(ans1.begin(),ans1.end());
            //小的数从大到小
            sort(ans2.begin(),ans2.end(),cmp);
            if(N<2*k)
                //小的数中后面一部分不影响,重新按升序
                sort(ans2.begin()+(N-k+1)/2,ans2.end());
            if(N&1){
                for(int i=0;i<k;i+=2){
                    ans.push_back(ans2[i/2]);
                    ans.push_back(ans1[i/2]);
                }
            }
            else{
                for(int i=0;i<k;i+=2){
                    ans.push_back(ans1[i/2]);
                    ans.push_back(ans2[i/2]);
                }
            }
            return ans;
        }
    }
};


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值