期望得分:60+ +0=60+
实际得分:30+56+0=86
时间规划极端不合理,T2忘了叉积计算,用解析几何算,还有的情况很难处理,浪费太多时间,最后gg
导致T3只剩50分钟,20分钟写完代码,没调出来
设sum[i][j] 表示字母j出现次数的前缀和
那么题目要求我们 最大化sum[r][x]-sum[l-1][x]-(sum[r][y]-sum[l-1][y])
如果枚举r,再枚举y,时间复杂度为O(n*26),是可以承受的
但此时还有l-1未知,能否O(1)找到l-1呢?
我们发现式子可以化为 :sum[r][x]-sum[r][y]-(sum[l-1][x]-sum[l-1][y])
这样减号两边形式相同
那就可以用前缀和来维护
所以设mi[i][j] 表示 当前 sum[i]-sum[j] 的最小值
在枚举r之前,l肯定已经计算过,所以sum的第一维可以不再mi中体现
那么ans=max(sum[r][x]-sum[r][y]-mi[x][y],sum[r][y]-sum[l][x]-mi[y][x])
小细节:
zhx的std中,
另外记录了当前每个字符的上一个出现的位置last[i],更新mi[i][j]的位置pos[i][j]
在更新答案的时候,是sum[r][x]-sum[r][y]-mi[x][y]-(pos[x][y]==last[i])
原因是因为 题目中要求 用来计算答案的 字母必须在所选区间出现过
std 每次在用sum更新mi时,不能保证用的这个字符出现过
还不明白的话 ,把std 的那句判等去掉,跑一遍数据:hhfffff
所以 我们仅需要在更新mi的时候,判断sum[]是否为真
便可以把这个特殊判断和last,pos 数组 去掉
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 1000001 int sum[N],mi[26][26]; char s[N]; int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); int n; scanf("%d",&n); scanf("%s",s+1); int ans=0; memset(mi,63,sizeof(63)); for(int i=1;i<=n;i++) { int now=s[i]-'a'; sum[now]++; for(int j=0;j<26;j++) if(sum[j]) ans=max(ans,max(sum[now]-sum[j]-mi[now][j],sum[j]-sum[now]-mi[j][now])); for(int j=0;j<26;j++) { if(sum[j] && sum[j]-sum[now]<mi[j][now]) mi[j][now]=sum[j]-sum[now]; if(sum[j] && sum[now]-sum[j]<mi[now][j]) mi[now][j]=sum[now]-sum[j]; } } printf("%d",ans); }