2017.10.14NOIP初赛上机测试

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值