2017-10-24 NOIP模拟赛

括号序列

(bracket)

Time Limit:1000ms   Memory Limit:128MB

 

题目描述

LYK有一个括号序列,但这个序列不一定合法。

一个合法的括号序列如下:

()是合法的括号序列。

若A是合法的括号序列,则(A)是合法的括号序列。

若A和B分别是合法的括号序列,则AB是合法的括号序列。

LYK想通过尽可能少的操作将这个不一定合法的括号序列变成合法的括号序列。一次修改操作是将某个字符变成另一个字符。

你能帮帮它吗?

 

输入格式(bracket.in)

    一行一个字符串S。

 

输出格式(bracket.out)

    一个数表示最少修改次数。

 

输入样例

()))

 

输出样例

1

 

样例解释

将第二个字符修改成(即可。

 

数据范围

对于30%的数据|S|<=10。

对于60%的数据|S|<=1000。

对于100%的数据|S|<=100000。且|S|是偶数。

/*
    这个题不能单纯判断左括号和右括号的多少,而应该从左到右扫一遍,看应该如何配对 
*/
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char s[100010];
int cnt,ans;
int main(){
    freopen("bracket.in","r",stdin);freopen("bracket.out","w",stdout);
    //freopen("Cola.txt","r",stdin);
    scanf("%s",s+1);
    int len=strlen(s+1);
    for(int i=1;i<=len;i++){
        if(s[i]==')'){
            if(cnt==0)cnt++,ans++;
            else cnt--;
        }
        else cnt++;
    }
    ans+=cnt/2;
    cout<<ans;
}
AC 模拟

 

公交车

(bus)

Time Limit:1000ms   Memory Limit:128MB

 

题目描述

LYK在玩一个游戏。

有k群小怪兽想乘坐公交车。第i群小怪兽想从xi出发乘坐公交车到yi。但公交车的容量只有M,而且这辆公交车只会从1号点行驶到n号点。

LYK想让小怪兽们尽可能的到达自己想去的地方。它想知道最多能满足多少小怪兽的要求。

当然一群小怪兽没必要一起上下车,它们是可以被分开来的。

 

输入格式(bus.in)

    第一行三个数k,n,M。

    接下来k行每行3个数xi,yi和ci。其中ci表示第i群小怪兽的小怪兽数量。

 

输出格式(bus.out)

    一个数表示最多有多少只小怪兽能满足要求。

 

输入样例

3 5 3

1 3 4

3 5 2

1 5 3

 

输出样例

5

 

样例解释

第一群的3只小怪兽在1号点上车,并在3号点下车。

第二群的2只小怪兽在3号点上车,5号点下车。

 

数据范围

对于30%的数据小怪兽的总数不超过10只,n<=10。

对于另外30%的数据k,n<=1000。

对于100%的数据1<=n<=20000,1<=k<=50000,1<=M<=100,1<=ci<=100,1<=xi<yi<=n。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int ans,n,m,c,w[20010];
struct node{
    int l,r,v;
    bool operator < (const node b)const{
        return r<b.r;
    }
}a[50010];
int main(){
    freopen("bus.in","r",stdin);freopen("bus.out","w",stdout);
    scanf("%d%d%d",&n,&m,&c);
    for(int i=1;i<=m;i++)w[i]=c;
    for(int i=1;i<=n;i++){
        scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].v);
        a[i].r--;
    }
    sort(a+1,a+n+1);
    for(int i=1;i<=m;i++){
        int mn=a[i].v;
        for(int j=a[i].l;j<=a[i].r;j++)mn=min(mn,w[j]);
        if(mn!=0){
            for(int j=a[i].l;j<=a[i].r;j++)w[j]-=mn;
            ans+=mn;
        }
    }
    printf("%d",ans);
}
60分 贪心+暴力
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int ans,n,m,c,w[20010],opl,opr,mn;
struct node{
    int l,r,v;
    bool operator < (const node b)const{
        return r<b.r;
    }
}a[50010];
struct Node{
    int l,r,v,lazy;
}tr[200010];
void update(int k){
    if(tr[k].l==tr[k].r){tr[k].lazy=0;return;}
    tr[k<<1].lazy+=tr[k].lazy;
    tr[k<<1].v+=tr[k].lazy;
    tr[k<<1|1].lazy+=tr[k].lazy;
    tr[k<<1|1].v+=tr[k].lazy;
    tr[k].lazy=0;
}
void build(int l,int r,int k){
    tr[k].l=l;tr[k].r=r;
    if(l==r){tr[k].v=c;return;}
    int mid=(l+r)>>1;
    build(l,mid,k<<1);
    build(mid+1,r,k<<1|1);
    tr[k].v=min(tr[k<<1].v,tr[k<<1|1].v);
}
int query(int l,int r,int k){
    if(tr[k].l>=opl&&tr[k].r<=opr){return tr[k].v;}
    if(tr[k].lazy!=0)update(k);
    int mid=(tr[k].l+tr[k].r)>>1;
    int res=0x7fffffff;
    if(opl<=mid)res=min(res,query(l,mid,k<<1));
    if(opr>mid)res=min(res,query(mid+1,r,k<<1|1));
    tr[k].v=min(tr[k<<1].v,tr[k<<1|1].v);
    return res;
}
void change(int l,int r,int k){
    if(l>=opl&&r<=opr){tr[k].lazy+=mn;tr[k].v+=mn;return;}
    if(tr[k].lazy!=0)update(k);
    int mid=(l+r)>>1;
    if(opl<=mid)change(l,mid,k<<1);
    if(opr>mid)change(mid+1,r,k<<1|1);
    tr[k].v=min(tr[k<<1].v,tr[k<<1|1].v);
}
int main(){
    //freopen("Cola.txt","r",stdin);
    freopen("bus.in","r",stdin);freopen("bus.out","w",stdout);
    scanf("%d%d%d",&n,&m,&c);
    build(1,m,1);
    for(int i=1;i<=n;i++)scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].v),a[i].r--;
    sort(a+1,a+n+1);
    for(int i=1;i<=n;i++){
        mn=a[i].v;
        opl=a[i].l,opr=a[i].r;
        mn=min(mn,query(1,m,1));
        ans+=mn;
        mn=-mn;
        if(mn!=0){change(1,m,1);}
    }
    printf("%d",ans);
    return 0;
}
100分 贪心+线段树

 

解谜游戏

(puzzle)

Time Limit:1000ms   Memory Limit:128MB

 

题目描述

LYK进了一家古董店,它很想买其中的一幅画。但它带的钱不够买这幅画。

幸运的是,老板正在研究一个问题,他表示如果LYK能帮他解出这个问题的话,就把这幅画送给它。

老板有一个n*m的矩阵,他想找一个和最大的子矩阵,这个子矩阵可以由四个参数x,y,x2,y2(1<=x<=x2<=n,1<=y<=y2<=m)来表示,表示一个左上角为(x,y),右下角为(x2,y2)的矩阵。

为了让游戏更加有趣,老板给了一个常数P,他想将原来这个矩阵中恰好一个数变为P,使得这个矩阵的最大的子矩阵尽可能大。

老板想知道这个最大值是多少。

你能帮帮LYK吗?

 

输入格式(puzzle.in)

    第一行三个数n,m,P。

    接下来n行,每行m个数ai,j描述整个矩阵。

 

输出格式(puzzle.out)

    输出一个数表示答案。

 

输入样例

3 3 3

-100 3 3

3 -4 3

3 3 3

 

输出样例

20

 

样例解释

改变左上角那个数。

 

数据范围

对于20%的数据n,m<=10。

对于40%的数据n,m<=25。

对于60%的数据n,m<=50。

对于80%的数据n,m<=100。

对于100%的数据1<=n,m<=300,|P|,|ai,j|<=1000。

#include<iostream>
#include<cstdio>
#include<cmath>
#define maxn 301
using namespace std;
int n,m,p,a[maxn][maxn],MIN[maxn],b[maxn],dp[maxn][2],s[maxn][maxn],ans=-0x7fffffff;
int main(){
    freopen("puzzle.in","r",stdin);freopen("puzzle.out","w",stdout);
    scanf("%d%d%d",&n,&m,&p);
    for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%d",&a[i][j]);
    for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)s[i][j]=s[i-1][j]+a[i][j];
    for(int i=1;i<=n;i++){//枚举上界 
        for(int j=1;j<=m;j++)MIN[j]=a[i][j];
        for(int j=i;j<=n;j++){//枚举下界 
            for(int k=1;k<=m;k++)MIN[k]=min(MIN[k],a[j][k]);//更新竖着的子段最小值 
            for(int k=1;k<=m;k++)b[k]=s[j][k]-s[i-1][k];dp[0][1]=-1000000000;
            for(int k=1;k<=m;k++){
                dp[k][0]=max(dp[k-1][0]+b[k],b[k]);
                dp[k][1]=max(max(dp[k-1][1]+b[k],dp[k-1][0]+b[k]-MIN[k]+p),b[k]-MIN[k]+p);
            }
            for(int k=1;k<m;k++)ans=max(ans,max(dp[k][0],dp[k][1]));
            if(i==1&&j==n){
                ans=max(ans,dp[m][1]);
                int sum=0;
                for(int k=m;k>1;k--)sum+=b[k],ans=max(ans,sum);
            }
            else ans=max(ans,max(dp[m][0],dp[m][1]));
        }
    }
    printf("%d",ans);
}
AC 前缀和+dp

 

posted @ 2017-10-24 14:21  Echo宝贝儿  阅读(338)  评论(0编辑  收藏  举报