[NOIP2016 提高组] 天天爱跑步
题面,题解就不打了,写的较好的题解。
主要是借这个题说一下如何正确的思考出来一道题:
首先样例肯定要模,在模的时候就是构建思路的过程,当然一般的小样例无论什么方法都可以得出答案(spj),能过正确的理解题面就行;
然后我们就可以顺着方案A想,看看是否有漏洞(反例)、复杂度(以这个题来说:每个人(跑m次)一遍一遍统计很好想出来,但稍微一分析就知道并不可行,但此时我们还不能轻易放弃它,想想怎么优化,深挖它的本质)、实现难度(得分效果);
如果不可行——转化思路,并不是换另一种等效做法!既然一个一个统计不行,就从整体着手;
如果可行(无论哪个方案):对于图的问题最好在纸上多动笔画画,推出一点眉目来就想想有没有不全or重复的情况;
分析的差不多了在考虑实现(多注意注意细节:如果不是一模一样就别先复制再改,容易少改某个地方;long long),最好要一气呵成。
既然是题解,怎么能没有代码呢?moo~~
#include<bits/stdc++.h>
#define Bessie moo~~
#define int long long
using namespace std;
inline int max(int a,int b){return a>b?a:b;}
inline int min(int a,int b){return a<b?a:b;}
int read(){
int A=0,FL=1;
char C=getchar();
while(C<'0'||C>'9')FL = C == '-' ? -1:1,C=getchar();
while(C>='0'&&C<='9')A=(A<<3)+(A*2)+(C^'0'),C=getchar();
return A*FL;
}
int T;
const int INF=1e9+7,N=5e3+5;
int n,m;
int a[N];
int f[N],zs[N][N],t[N];//众数的频数
int ans;
bool il(int x,int y){
if(x>y)return 1;
return zs[x][y]<=((y-x+1)>>1);
}
signed main(){
T=read();
while(T--){
n=read();
ans=0;
for(int i=1;i<=n;i++){
a[i]=read();
f[i]=0;
}
for(int i=1;i<=n;i++){
int tmp=0;
for(int j=i;j<=n;j++){
t[a[j]]++;
if(t[a[j]]>t[tmp])tmp=a[j];
zs[i][j]=t[tmp];
}
for(int j=i;j<=n;j++){
t[a[j]]=0;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++){
if(j>1&&a[j-1]!=a[i])continue;
if(((i-1)-j+1)&1)continue;//[j,i)长度为奇数不能完全删除
if(il(j,i-1))f[i]=max(f[i],f[j-1]+1);
}
if(f[i]==0)f[i]=-INF;
// printf("f[%lld] = %lld\n",i,f[i]);
}
for(int i=1;i<=n;i++){
if((n-(i+1)+1)%2==0&&il(i+1,n))
ans=max(ans,f[i]);
}
printf("%lld\n",ans);
}
return 0;
}