Problem 1 :
题目描述
今年开始上学的 DQS 非常喜欢石子, 她总是会收集很多不同类型的石子来卖钱, 这个世界的石子只有两种——蓝色和白色(用01 表示) 并且都是连在一起的, 不能移动, 因此 DQS 只好使用她的神力来解除石子不能移动的封印, 但是由于某些原因 DQS 希望让自己消耗更多的神力, 因此她许愿黑暗之神让她可以转换连在一起的石子中的一颗。 消耗的神力计算方法为这一串石子中相邻相同的石子个数的平方和。 DQS 想知道, 如何改变其中一个石子的种类, 使得整个石子串的消耗最大(含多组数据)
输入描述 一个数 T接下来 T 行, 每行一个长度为 N 的 01 串
输出描述 一个数 p 表示 DQS 消耗的神力
样例输入
2
000011
0101
样例输出
26
10
数据范围及提示
1<=T<=50
60%:1<=N<=1000
100%:1<=N<=100000
思路
处理出初始答案(不进行修改)和连续的0|1区间范围,尝试将每一个元素修改求出当前消耗总和,对于不在区间边缘的元素可以忽略。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define RI register int
using namespace std;
int t,len,tot;
int pos[100010];//属于哪一个区间
long long sum,ans,tmp,ans1;
bool bs[100010],bt[100010];//左边,右边
string num;
struct inte
{
int ans1,ans2;
}l[100010];//点
struct ren
{
int l,r;
}p[100010];//区间
int main()
{
scanf("%d",&t);
for(RI i=1;i<=t;i++)
{
memset(bs,0,sizeof(bs));
memset(bt,0,sizeof(bt));
memset(l,0,sizeof(l));//初始化注意
cin>>num;
len=num.length();
sum=1;
ans=0;
for(RI i=0;i<len-1;i++)//预处理初始答案
{
if(num[i]==num[i+1])
sum++;
else
{
ans+=sum*sum;
sum=1;
}
}
ans+=sum*sum;
ans1=ans;
if(num[0]!=num[1])//确定每一位置是否为相同元素区间的开始和结束位置(左右是否不同)
bt[0]=1;
for(RI i=1;i<len-1;i++)
{
if(num[i]!=num[i-1])
bs[i]=1;
if(num[i]!=num[i+1])
bt[i]=1;
}
if(num[len-1]!=num[len-2])
bs[len-1]=1;
tot=1;
p[tot].l=0;
for(RI i=0;i<len;i++)//处理每个区间长度
{ //不可以直接选取使最大区间最大的方案,因为周边区间的消耗也会变化影响答案
pos[i]=tot;
if(bs[i])
{
p[tot].l=i;
for(int j=i-1;j>=0;j--)
{
if(num[j]==num[i])
break;
l[i].ans1++;
}
}
if(bt[i])
{
p[tot++].r=i;
for(int j=i+1;j<len;j++)
{
if(num[j]==num[i])
break;
l[i].ans2++;
}
}
}
if(bs[len-1])
{
p[tot].l=p[tot].r=len-1;
}
else p[tot].r=len-1;
tmp=0;
for(RI i=0;i<len;i++)//枚举每个位为改变的位置
{
if(!bs[i]&&!bt[i])
continue;
if(bs[i]&&bt[i])//计算此时答案
{
tmp=ans-(l[i].ans1*l[i].ans1)-(l[i].ans2*l[i].ans2)+((l[i].ans1+l[i].ans2+1)*(l[i].ans1+l[i].ans2+1))-1;
}
if(bs[i]&&!bt[i])
{
tmp=ans-(l[i].ans1*l[i].ans1)-((p[pos[i]].r-p[pos[i]].l+1)*(p[pos[i]].r-p[pos[i]].l+1))+((l[i].ans1+1)*(l[i].ans1+1))+((p[pos[i]].r-p[pos[i]].l)*(p[pos[i]].r-p[pos[i]].l));
}
if(!bs[i]&&bt[i])
{
tmp=ans-(l[i].ans2*l[i].ans2)-((p[pos[i]].r-p[pos[i]].l+1)*(p[pos[i]].r-p[pos[i]].l+1))+((l[i].ans2+1)*(l[i].ans2+1))+((p[pos[i]].r-p[pos[i]].l)*(p[pos[i]].r-p[pos[i]].l));
}
ans1=max(ans1,tmp);
}
printf("%lld\n",ans1);
}
return 0;
}