2017.10.14NOIP初赛上机测试

来源:互联网 发布:绵阳cnc编程招聘 编辑:程序博客网 时间:2024/06/05 16:53

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 intusing 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;}
原创粉丝点击