转载请注明出处,谢谢 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; } };
有三种颜色的球,堆成高度为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; } */ } };
还是要继续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; } } };