10.15 loitest 未完

11 篇文章 0 订阅
8 篇文章 0 订阅

出题人

swc学长 http://blog.csdn.net/wwwasdirine

Problem 1 DQS 捡石子

题目来源

https://vjudge.net/problem/HDU-5583

题目描述

今年开始上学的 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

题解

通过正序和逆序两遍循环,我们可以处理出以任意元素为起点和终点的相同序列的长度
计算出一个初始的答案
然后枚举每一个元素作为改变的位置(显然改变序列中部一定不会最优,可以跳过)
大致分为下列三种情况
0011
改变第二位的0 某个序列的末尾元素
第三位的1 某个序列的初始元素
010
改变1 两个序列之间的唯一元素

将ans进行加减,取max

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=100000+50;
long long ed[N],be[N],len;
char a[N];
long long ans,maxx,tmp;
long long t;
long long  pf(long long  x){
    long long ha=x*x;
    return ha;
}
void done(){
    for(int i=1;i<=len;i++){
        if(a[i]==a[i-1]){
            ed[i]=ed[i-1]+1;
        }
        else {
            ans+=ed[i-1]*ed[i-1];
            ed[i]=1;    

        }
    }
    ans+=pf(ed[len]);
    for(int i=len;i>=1;i--){
        if(a[i]==a[i+1]){
            be[i]=be[i+1]+1;
        }
        else be[i]=1;
    }
}

void init(){
    maxx=-1;
    ans=0;
    memset(ed,0,sizeof(ed));
    memset(be,0,sizeof(be));
    return ;
}
void done1(int i){
    tmp=ans;
    tmp-=pf(ed[i-1]);
    tmp+=pf(ed[i-1]+1);
    tmp-=pf(be[i]);
    tmp+=pf(be[i]-1);
    maxx=max(tmp,maxx);
}
void done2(int i){
    tmp=ans;
    tmp-=pf(ed[i]);
    tmp+=pf(ed[i]-1);
    tmp-=pf(be[i+1]);
    tmp+=pf(be[i+1]+1);
    maxx=max(tmp,maxx);
}
void done3(int i){
    tmp=ans;
    tmp-=pf(ed[i-1]);
    tmp-=pf(be[i+1]);
    tmp-=1;
    tmp+=pf(ed[i-1]+be[i+1]+1);
    maxx=max(tmp,maxx);
}
int main(){

    scanf("%lld",&t);
    for(int ha=1;ha<=t;ha++){
        init();
        cin>>a+1;
        len=strlen(a+1);
        done();
        maxx=ans;
        for(int i=2;i<len;i++){
            if(a[i-1]==a[i]&&a[i]==a[i+1]) continue;
            if(a[i]!=a[i-1]&&a[i]==a[i+1]){
                done1(i);
            }
            if(a[i]==a[i-1]&&a[i]!=a[i+1]){
                done2(i);
            }
            if(a[i]!=a[i-1]&&a[i]!=a[i+1]){
                done3(i);
            }
        }

        if(a[1]!=a[2]){
            tmp=ans;
            tmp-=1;
            tmp-=pf(be[2]);
            tmp+=pf(be[2]+1);
            maxx=max(tmp,maxx);
        } 
        if(a[len]!=a[len-1]){
            tmp=ans;
            tmp-=1;
            tmp-=pf(ed[len-1]);
            tmp+=pf(ed[len-1]+1);
            maxx=max(tmp,maxx);
        }

        printf("Case #%d: %lld\n",ha,maxx);
    }
}

Problem 2 DQS 讲笑话

题目来源

https://vjudge.net/problem/Gym-101350F

题目描述

在一个平行世界中, 生活着无数只 DQS。 这里的 DQS 不喜欢捡石子, 她们只喜欢讲笑话。 一天, 有 n 只DQS 坐在一起讲笑话, 有 m 次讲笑话的机会。由于这个世界的 DQS太喜欢讲笑话了, 所以很多笑话她们都是讲过的。 因此这一次DQS 们讲笑话时也是从现有的笑话库中找笑话出来讲, 每次 DQS讲第 li 种笑话, 影响的范围是向左向右 ki 只 DQS, 同时自己也会受到影响。 一只 DQS 如果听到了一个没听过的笑话会笑趴下,但她如果听到了一个听过的笑话会坐起来。 一开始所有的 DQS 都是坐着的。
问最后有多少 DQS 是坐着的呢

输入描述
第一行两个数 n,m
接下来 m 行 每行三个数 xi(表示第几只 DQS 讲笑话) ,li(第几种笑话) ,ki(影响 2ki+1 只 DQS)

输出描述
一个数 p, 表示有 p 只 DQS 最后是坐着的

样例输入
10 7
3 11 0
3 11 2
5 12 1
8 13 2
7 11 2
10 12 1
9 12 0

样例输出
3

数据范围及提示
对于 30% n<=100, m<=100
对于 60% n<=10000,m<=10000
对于 100% n<=100000,m<=100000, 1<=li<=100000
1<=x<=n,0<=k<=n

题解:

首先,可以明确的是,某点最终的状态,取决于它听到的最后一个笑话
若听到的最后一个笑话是第一次 ans不更新
不是第一次 ans更新
从未听到过笑话 ans更新

还有别的做法

一:stl法

http://blog.csdn.net/fanesemyk/article/details/76557632
借鉴了这位大佬很多

开一个vector的二维数组,读入每一条线段,在始点push进去笑话的编号,在末点的下一位push进去笑话的编号的相反数(负值)
运用set元素唯一且能迅速查询删除指定大小的元素的功能
我们从第一个点开始循环
如果vector中有一个正值,说明有一个笑话从这个点开始,丢入set,如果有一个负值,说明有一个笑话到这里结束,从set中删除,更新num数组(表示每个笑话出现的次数)
某点i循环完毕后,
若set为空,说明某点根本就没有笑话,ans++
若set不为空,那么set的末尾元素就是该点听到的最后一个笑话,如果对应的num>1,说明笑话出现了不止一次 ans++
由于是从一开始枚举,不存在遗漏当前节点的笑话的情况

将笑话按照顺序进行编号,对应起来,避免了两个部分重叠的相同笑话的线段在进行set操作时的错误情况,同时又维护了每个笑话出现的次数

这里写图片描述
如图如果不进行编号,而是按照笑话的种类,在执行到黄点时,当前笑话就会被弹出set,从黄点到绿点这一部分的笑话就会失去

代码:

stl代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<set>
#include<vector>
#include<cstring>
using namespace std;
int n,m,x,l,k;
const int N=100000+500;
int num[N],type[N],ans;
vector<int> e[N];
set<int> s;
void init(){
    for(int i=0;i<=n+3;i++) e[i].clear();
    s.clear();
    ans=0;
    memset(num,0,sizeof(num));
    memset(type,0,sizeof(type));
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        init();
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&x,&l,&k);
            type[i]=l;
            int z=max(1,x-k),y=min(n,x+k);
            e[z].push_back(i);
            e[y+1].push_back(-i);
        }
        for(int i=1;i<=n;i++){
            int sz=e[i].size();
            for(int j=0;j<sz;j++){
                int t=e[i][j];
                if(t>0){
                    s.insert(t);
                    num[type[t]]++;
                }
                else{
                    s.erase(-t);
                    num[type[-t]]--;
                }
            }
            if(s.empty()) ans++;
            else{
                int p=*(--s.end());

                if(num[type[p]]>1) ans++;
            }
        }
        printf("%d\n",ans); 
    }
    return 0;
}

Problem 3 DQS 找宝藏

题目来源

http://www.lydsy.com/JudgeOnline/problem.php?id=1924

题目描述

另一个平行世界中的 DQS 既不喜欢捡石子也不喜欢讲笑话, 她们喜欢—
—寻宝!
于是这一天 DQS 来到一个沉睡着古神的神殿中来探宝整座宫殿呈矩阵状,由 R×C 间矩形宫室组成,其中有 N 间宫室里埋藏着宝藏,称作藏宝宫室。 宫殿里外、 相邻宫室间都由坚硬的实体墙阻隔,由一间宫室到达另一间只能通过古神独创的移动方式——传送门。 古神为这N 间藏宝宫室每间都架设了一扇传送门,没有宝藏的宫室不设传送门,所有的宫室传送门分为三种:
1、 “横天门” :由该门可以传送到同行的任一宫室;
2、 “纵寰门” :由该门可以传送到同列的任一宫室;
3、 “自由门” :由该门可以传送到以该门所在宫室为中心周围 8 格中任一宫室(如果目标宫室存在的话)。
深谋远虑的 DQS 当然事先就搞到了古神当年的宫殿招标册,书册上详细记录了每扇传送门所属宫室及类型。 而且,虽然宫殿内外相隔,但他自行准备了一种便携式传送门,可将自己传送到殿内任意一间宫室开始寻宝,并在任意一间宫室结束后传送出宫。 整座宫殿只许进出一次,且便携门无法进行宫室之间的传送。 不过好在宫室内传送门的使用没有次数限制,每间宫室也可以多次出入。
现在 DQS 已经打开了便携门,即将选择一间宫室进入。 为得到尽多宝藏,他希望安排一条路线,使走过的不同藏宝宫室尽可能多。请你告诉 DQS 这条路 线最多行经不同藏宝宫室的数目。

输入描述
第一行给出三个正整数 N, R, C。
以下 N 行,每行给出一扇传送门的信息,包含三个正整数
xi, yi, Ti,表示该 传送门设在位于第 xi 行第 yi 列的
藏宝宫室,类型为 Ti。
Ti 是一个 1~3 间的整数,
1 表示可以传送到第 xi 行任意一列的“横天门” ,
2 表示可以传送到任意一行第 yi 列的“纵寰门” ,
3 表示可以传送到周围 8 格宫室的“自由门” 。
保证 1≤xi≤R,1≤yi≤C,所有的传送门位置互不相同。

输出描述
只有一个正整数,表示你确定的路线所经过不同藏宝 宫室
的最大数目。

样例输入
10 7 7
2 2 1
2 4 2
1 7 2
2 7 3
4 2 2
4 4 1
6 7 3
7 7 1
7 5 2
5 2 1

样例输出
9
数据范围及提示
测试点编号 N R C
1 16 20 20
2 300 1,000 1,000
3 500 100,000 100,0004 2,500 5,000 5,000
5 50,000 5,000 5,000
6 50,000 1,000,000 1,000,000
7 80,000 1,000,000 1,000,000
8 100,000 1,000,000 1,000,000
9 100,000 1,000,000 1,000,000
10 100,000 1,000,000 1,000,000 保证每次询问的数均在序列内

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值