10.1综合强化刷题 Day3
括号序列(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|是偶数。
一个比较水的题,似乎就是一个比较裸地括号匹配。我们可以用一个比较简单的栈模拟(我用的是队列模拟)就可以A掉的、、
我们每次读入一个字符,然后判断如果这个字符是(那么我们让他进队,即tail++,然后如果读入的字符是一个)那么我们判断在这个字符的前面时候存在(,如果存在,我们就讲这个()全部消掉,即队中的一定只是(,那我们消掉的时候只要让他tail--就好了,当然我们要保证head<=tail。如果对中没有(可以将)消掉,那么说明这个)一定是不合法的我们一定要将这个)进行修改,改成(然后将其入队,tail++。
我们一直这样处理,最后一定会出现这样的情况((((((,如果有)的会就被消掉了啊。。。那么我们只需要将后面的(修改成)就好了,也就是说我们最后进行修改的个数极为(的个数除以2,(的个数即为队中元素的个数,队中的元素的个数为head。
这样这道题就已经AC了
来,看看代码、、、
#include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define N 100010 using namespace std; char s[N]; int head,tail,ans; int read() { ,f=; char ch=getchar(); ') ch=getchar(); +ch-',ch=getchar(); return x*f; } int main() { freopen("bracket.in","r",stdin); freopen("bracket.out","w",stdout); cin>>s; head=tail=; int l=strlen(s); ;i<l;i++) { if(s[i]=='(') tail++; else { if(tail>head) tail--; else tail++,ans++; } } ; printf("%d",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。
不会正解打了个搜索,碰到了30分、、
#include<queue> #include<cstdio> #include<vector> #include<cstring> #include<iostream> #include<algorithm> #define N 20010 using namespace std; int n,m,k,ans,sum[N]; int read() { ,f=; char ch=getchar(); ; ch=getchar();} +ch-',ch=getchar(); return x*f; } struct node { int to,val; node() {} node(int to,int val):to(to),val(val) {} }; vector<node>G[N]; void DFS(int num,int s,int people) { ) { ans=max(ans,s); return; } people+=sum[num]; sum[num]=; ;i<G[num].size();++i) { int v=G[num][i].to; int ps=G[num][i].val; if(ps<=k-people) { sum[v]+=-ps; DFS(num+,s+ps,people+ps); } else if((people<k)&&(ps+people>k)) { sum[v]+=people-k; DFS(num+,s+k-people,k); } } DFS(num+,s,people); return; } int main() { freopen("bus.in","r",stdin); freopen("bus.out","w",stdout); m=read(),n=read(),k=read(); int x,y,z; ;i<=m;++i) { x=read(),y=read(),z=read(); G[x].push_back(node(y,z)); } DFS(,,); printf("%d\n",ans); ; }
dfs
看到这个题后我们脑子里一定会闪过这样一个经典题目,有n个区间,找尽可能多的区间使得区间之间互不相交。(啊,这不就是线段覆盖那道题吗?!)
对于这道经典的题目我们使用的贪心的做法,将所有的线段按右端点进行排序枚举每一个区间,然后按照能取就取的原则进行贪心。
但是这个题和那个经典题目是有很大的区别的,我们在这个经典问题中的线段是不能相交的,并且我们知道车有一个容量,我们每次都可以上c(容量)的人。
我们对于每一个区间,求这一群怪兽能过几只 维护一个f数组 f[i]表示i这个时刻 车上已经坐了几只怪兽了
[X,Y] Z
for (int i=X; i<Y; i++)
MAX=max(MAX,f[i]);
t=min(Z,M-MAX);
for (int i=X; i<Y; i++) f[i]+=t;
ans+=t
cout<<ans;
1.区间加 2.区间查询最大值,看到这两个操作,我们就可以很容易的想到线段树了 这样的时间复杂度为 klgn
这样这个事情就干完了、、
具体的来说就是我们先按右端点进行排序,然后对于每一个怪兽在车上呆的区间进行一个区间查询,然后在能上就上进行一下区间修改,最后统计个数,这样就搞定了
来,上代码
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define N 100005 using namespace std; int n,m,c,a,b,x,q,p,ans,minn; int read() { ,f=; char ch=getchar(); ; ch=getchar();} +ch-',ch=getchar(); return x*f; } struct Tree { int l,r,w,f; }tree[N]; struct Node { int x,y,z; }node[N]; int cmp(Node a,Node b) { return a.y<b.y; } void build(int k,int l,int r) { tree[k].l=l,tree[k].r=r; if(tree[k].l==tree[k].r) { tree[k].w=c; return ; } ; build(k<<,l,mid); build(k<<|,mid+,r); tree[k].w=tree[k<<].w+tree[k<<|].w; } void down(int k) { tree[k<<].f+=tree[k].f; tree[k<<|].f+=tree[k].f; tree[k<<].w+=(tree[k<<].r-tree[k<<].l+)*tree[k].f; tree[k<<|].w+=(tree[k<<|].r-tree[k<<|].l+)*tree[k].f; tree[k].f=; } void change(int k) { if(tree[k].l>=a&&tree[k].r<=b) { tree[k].w+=(tree[k].r-tree[k].l+)*x; tree[k].f+=x; return ; } if(tree[k].f) down(k); ; ); |); tree[k].w=tree[k<<].w+tree[k<<|].w; } void ask(int k) { if(tree[k].r<a||tree[k].l>b) return ; if(tree[k].l==tree[k].r) { minn=min(minn,tree[k].w); return ; } if(tree[k].f) down(k); ; ); |); } int main() { m=read(),n=read(),c=read(); build(,,n); ;i<=m;i++) { node[i].x=read(),node[i].y=read(); node[i].z=read();node[i].y--; } sort(node+,node++m,cmp); ;i<=m;i++) { a=node[i].x,b=node[i].y; minn=); ),ans+=node[i].z; ),ans+=minn; } printf("%d",ans); }
诡异的60分的线段树做法
区间求最小值的时候进行修改的时候只修改一个点的值,因为我们线段树维护的是最小值,而非和
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define N 100005 using namespace std; int n,m,c,a,b,x; long long ans,minn; int read() { ,f=; char ch=getchar(); ; ch=getchar();} +ch-',ch=getchar(); return x*f; } struct Tree { int l,r; long long w,f; }tree[N<<]; struct Node { int x,y,z; }node[N]; int cmp(Node a,Node b) { return a.y<b.y; } void build(int k,int l,int r) { tree[k].l=l,tree[k].r=r; if(tree[k].l==tree[k].r) { tree[k].w=c; return ; } ; build(k<<,l,mid); build(k<<|,mid+,r); tree[k].w=min(tree[k<<].w,tree[k<<|].w); } void down(int k) { tree[k<<].f+=tree[k].f; tree[k<<|].f+=tree[k].f; tree[k<<].w+=tree[k].f; tree[k<<|].w+=tree[k].f; tree[k].f=; } void change(int k) { if(tree[k].l>=a&&tree[k].r<=b) { tree[k].w+=x; tree[k].f+=x; return ; } if(tree[k].f) down(k); ; ); |); tree[k].w=min(tree[k<<].w,tree[k<<|].w); } void ask(int k) { if(tree[k].l>=a&&tree[k].r<=b) { minn=min(minn,tree[k].w); return ; } if(tree[k].f) down(k); ; ); |); } int main() { m=read(),n=read(),c=read(); build(,,n); ;i<=m;i++) { node[i].x=read(),node[i].y=read(); node[i].z=read();node[i].y--; } sort(node+,node++m,cmp); ;i<=m;i++) { a=node[i].x,b=node[i].y; minn=); ),ans+=node[i].z; ),ans+=minn; } printf("%lld",ans); }
AC代码
解谜游戏(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。
看到这个题,我们应该脑子里会蹦出这样的一个大水题吧:http://www.cnblogs.com/z360/p/7608115.html这是我们之前做过的·一道求最大矩形的题。
当时的这道题我们是这样做的:预处理出每一行的前缀和,然后暴力枚举矩形的上边界以及下边界,然后在枚举列,每当统计出的s出现负值,则说明出现了被吃掉的巧克力,更新s为0,然后在继续枚举。
#include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define N 500 #define maxn 0x7fffffff using namespace std; long long n,m,s,x,y,a[N][N],sum[N][N],v1[N],v2[N],ans; int main() { scanf("%lld%lld",&n,&m); ;i<=n;i++) ;j<=m;j++) { scanf("%lld",&a[i][j]); if(!a[i][j]) a[i][j]=-maxn; sum[i][j]+=sum[i-][j]+a[i][j]; } ;i<n;i++) ;j<=n;j++) { ;k<=m;k++) { s+=sum[j][k]-sum[i][k]; ) s=; ans=max(ans,s); } s=; } printf("%lld",ans); ; }
我们看着两个题的不同点,这个题我们要在这个矩形内改一个数来是这个矩形内的所有数的和变大,那么我们可以枚举将哪个点进行修改,N^2枚举需要进行修改的点,然后我们在采取上面的做法,我们就可以把N^5的得出答案。
我们考虑一下怎么进行优化,我们知道我们要讲一个矩形内的数进行修改的话,我们考虑修改呢个数对这个矩形造成的(负面)影响最小,即为是这个矩形尽可能地大,我们是不是就要找一个最小的数进行修改。那么我们可以预处理出每一个矩形内的最小值,以及每一个矩形内的所有数的和。然后我们N^4枚举一个矩形的左上角以及右下角,
(明明打了个60分的做法,但是由于题目意思理解的不是很透彻,然后wa掉了好几个点、、题目中说必须要改一个点的权值但是改的这个权值不一定要是我们选定的这个矩形,那么我们呢是不是就可以判断一下我们的最大的矩形是否为整个矩形,如果是整个矩形的话我们一定要改一个点,但是我们选出的这个矩形若不是整个矩形,我们可以改这个矩形以外的点也就是说我们可以将改与不改取一个max,这样应该就可以拿到60分)
#include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define N 55 #define LL long long using namespace std; int n,m,p,a[N][N],minn[N][N][N][N],sum,ans,s[N][N][N][N]; int read() { ,f=; char ch=getchar(); ; ch=getchar();} +ch-',ch=getchar(); return x*f; } int main() { freopen("puzzle.in","r",stdin); freopen("puzzle.out","w",stdout); n=read(),m=read(),p=read(); int m1,m2; memset(minn,,sizeof(minn)); ;i<=n;i++) ;j<=m;j++) a[i][j]=read(); ;h1<=n;h1++) ;l1<=m;l1++) for(int h2=h1;h2<=n;h2++) for(int l2=l1;l2<=m;l2++) { s[h1][l1][h2][l2]=s[h1][l1][h2-][l2]+s[h1][l1][h2][l2-]+a[h2][l2]-s[h1][l1][h2-][l2-]; m1=min(minn[h1][l1][h2-][l2-],a[h2][l2]),m2=min(minn[h1][l1][h2-][l2],minn[h1][l1][h2][l2-]); minn[h1][l1][h2][l2]=min(m1,m2); } ;h1<=n;h1++) ;l1<=m;l1++) for(int h2=h1;h2<=n;h2++) for(int l2=l1;l2<=m;l2++) { sum=s[h1][l1][h2][l2]; ans=max(ans,sum-minn[h1][l1][h2][l2]+p); } printf("%d",ans); ; }
40分
唉,改过对题意理解不清的那个地方就是60分了,呜呜、、、
#include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define N 55 #define LL long long using namespace std; int n,m,p,a[N][N],minn[N][N][N][N],sum,ans,s[N][N][N][N]; int read() { ,f=; char ch=getchar(); ; ch=getchar();} +ch-',ch=getchar(); return x*f; } int main() { n=read(),m=read(),p=read(); int m1,m2; memset(minn,,sizeof(minn)); ;i<=n;i++) ;j<=m;j++) a[i][j]=read(); ;h1<=n;h1++) ;l1<=m;l1++) for(int h2=h1;h2<=n;h2++) for(int l2=l1;l2<=m;l2++) { s[h1][l1][h2][l2]=s[h1][l1][h2-][l2]+s[h1][l1][h2][l2-]+a[h2][l2]-s[h1][l1][h2-][l2-]; m1=min(minn[h1][l1][h2-][l2-],a[h2][l2]),m2=min(minn[h1][l1][h2-][l2],minn[h1][l1][h2][l2-]); minn[h1][l1][h2][l2]=min(m1,m2); } ;h1<=n;h1++) ;l1<=m;l1++) for(int h2=h1;h2<=n;h2++) for(int l2=l1;l2<=m;l2++) { sum=s[h1][l1][h2][l2]; &&l1==&&h2==n&&l2==m) ans=max(ans,sum-minn[h1][l1][h2][l2]+p); else ans=max(ans,sum-minn[h1][l1][h2][l2]+max(p,minn[h1][l1][h2][l2])); } printf("%d",ans); ; }
60分代码
我们再来看AC做法
老师讲解:枚举左上角 n^ 枚举右下角n^ 枚举修改的数 n^ 求和 n^ -> n^ 求一个矩阵和,可以通过矩阵前缀和做到O() 枚举左上角 n^ 枚举右下角n^ 枚举修改的数 n^ -> n^ 预处理出每个矩阵的最小值是多少。 n^ 枚举左上角 n^ 枚举右下角n^ 修改的数已知(修改最小的或者不修改) -》n^ n,m<= 假如我们不要求修改数,查询最大子矩阵 有n个数,查询最大子段和 O(n) ; i<=n; i++) f[i]=max(f[i-]+a[i],a[i]); max{f[i]} = 最大子段和 要求我们修改数 修改的数一定是最小的那个数。 f[i][]以i结尾并且没有数被修改过的最大和 f[i][]以i结尾并且有数被修改过的最大和 //a[i] 第i列的和 ; i<=n; i++) { f[i][]=max(f[i-][]+a[i],a[i]); f[i][]=max(f[i-][]+a[i],f[i-][]+a[i]-MIN[i]+P,a[i]-MIN[i]+P); } max{f[?][/]} 是答案 恰好改变一个数
代码:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define N 305 using namespace std; int n,m,p,ans,d[N],s[N][N],minn[N],a[N][N],dp[N][N]; int read() { ,f=; char ch=getchar(); ; ch=getchar();} +ch-',ch=getchar(); return x*f; } int main() { n=read(),m=read(),p=read(); ans=-;//一定要记得赋初值 ;i<=n;i++) ;j<=m;j++) a[i][j]=read(),s[i][j]=s[i-][j]+a[i][j];//预处理前缀和 ;i<=n;i++)//枚举上边界 { ;j<=m;j++) minn[j]=a[i][j];//预处理每一列里的最小值 for(int j=i;j<=n;j++)//枚举下边界 { ;k<=m;k++) minn[k]=min(minn[k],a[j][k]);// ;k<=m;k++) d[k]=s[j][k]-s[i-][k];//处理出在上边界与下边界围成的这个地方每一列的和 dp[][]=-;//赋初值 ;k<=m;k++) { dp[k][]=max(dp[k-][]+d[k],d[k]);//dp[k][0]表示到k这一列还没有修改的情况 ,这种情况只能从两种状态转移过来,一种是他前面哪一行再加上这一行,还有一种是直接从这一行开始 dp[k][]=max(max(dp[k-][]+d[k],d[k]-minn[k]+p),dp[k-][]+d[k]-minn[k]+p);//dp[k][1]表示到k这一列已经修改了一个地方 } //这个有三种转移,一种是在这之前已经修改了然后再加上这一行,一种是直接从这一行开始那么要从这一行中选出一个数来进行修改,一种是在这一行之前没有修改过的要在这一行中选一个数进行修改 &&j==n)//判断是整个矩形的情况,那么这种情况下必须要在选出的这个矩形中修改一个数 ans=max(ans,dp[m][]); else ;k<=m;k++) ans=max(ans,max(dp[k][],dp[k][]));//其他的情况下,我们可以从在我们选定的矩形中修改与不修改选一个大的 } } printf("%d",ans); ; }
AC代码
10.1综合强化刷题 Day3的更多相关文章
- 10.1综合强化刷题 Day3 morning
竞赛时间:????年??月??日??:??-??:?? 题目名称 a b c 名称 a b c 输入 a.in b.in c.in 输出 a.out b.out c.out 每个测试点时限 1s 1s ...
- 10.1综合强化刷题 Day3 afternoon
竞赛时间:????年??月??日??:??-??:?? 题目名称 a b c 名称 a b c 输入 a.in b.in c.in 输出 a.out b.out c.out 每个测试点时限 1s 1s ...
- 10.1综合强化刷题 Day2 morning
一道图论神题(god) Time Limit:1000ms Memory Limit:128MB 题目描述 LYK有一张无向图G={V,E},这张无向图有n个点m条边组成.并且这是一张带权图,只有 ...
- 10.1综合强化刷题 Day2 afternoon
最大值(max) Time Limit:1000ms Memory Limit:128MB 题目描述 LYK有一本书,上面有很多有趣的OI问题.今天LYK看到了这么一道题目: 这里有一个长度为n的 ...
- 10.1综合强化刷题 Day7
noip提高组模拟赛 ...
- 10.1综合强化刷题 Day1 afternoon
一道图论好题(graph) Time Limit:1000ms Memory Limit:128MB 题目描述 LYK有一张无向图G={V,E},这张无向图有n个点m条边组成.并且这是一张带权图, ...
- 10.1综合强化刷题 Day6
T1 排序 题目描述 小Z 有一个数字序列a1; a2; .... ; an,长度为n,小Z 只有一个操作:选 定p(1<p<n),然后把ap 从序列中拿出,然后再插⼊到序列中任意位置. ...
- 10.1综合强化刷题 Day5
T1 拼不出的数 lost.in/.out/.cpp[问题描述]3 个元素的集合{5; 1; 2}的所有子集的和分别是0; 1; 2; 3; 5; 6; 7; 8.发现最小的不能由该集合子集拼出的数字 ...
- 10.1综合强化刷题 Day4
财富(treasure) Time Limit:1000ms Memory Limit:128MB 题目描述 LYK有n个小伙伴.每个小伙伴有一个身高hi. 这个游戏是这样的,LYK生活的环境是以 ...
随机推荐
- 配置Wampserver和安装thinksns
一.先安装Wampserver(去官网下载) 二.安装好后单击wampserver图标,Apache->Service->测试80端口,如果显示: i 端口被iis占用 控制面板-> ...
- 自我介绍&友链
目录 此博客 我是谁? 友链 此博客 此博客主要更新一些题解什么的...(随缘啦) 本蒟蒻太菜了,博客中出现了错误希望指出,谢谢! . . 我是谁? SD的一名蒟蒻!emm... 喜欢摸鱼. 喜欢抽卡 ...
- ffmpeg转换参数和对几种视频格式的转换分析
我们在将多种格式的视频转换成flv格式的时候,我们关注的就是转换后的flv视频的品质和大小.下面就自己的实践所得来和大家分享一下,主要针对avi.3gp.mp4和wmv四种格式来进行分析.通常在使用f ...
- php字符串 函数
strtolower()//字符串转化小写的字母 $str="abcdEfG";$s=strtolower($str); 输出:abcdefg; strtoupper();字符串转 ...
- python 类中__init__,__new__,__class__的使用详解
1.python中所有类默认继承object类,而object类提供了很多原始的内置属性和方法,所有用户定义的类在python 中也会继承这些内置属性.我们可以通过dir()进行查看.虽然python ...
- 双网卡只有一个能ping通的解决办法
来源:http://blog.csdn.net/centerpoint/article/details/38542719 Linux默认启用了反向路由检查 如果2个网卡在一个Lan里面,那么服务器可能 ...
- 团队Alpha版本冲刺(二)
目录 组员情况 组员1(组长):胡绪佩 组员2:胡青元 组员3:庄卉 组员4:家灿 组员5:凯琳 组员6:丹丹 组员7:家伟 组员8:政演 组员9:黄鸿杰 组员10:刘一好 组员11:何宇恒 展示组内 ...
- Vue2.0 - 构造器的延伸 Vue.extend
Vue.extend 返回的是一个“扩展实例构造器”,也就是预设了部分选项的Vue实例构造器.经常服务于Vue.component用来生成组件,可以简单理解为当在模板中遇到该组件名称作为标签的自定义元 ...
- hihoCoder #1867 GCD
在集合 $[n]$ 上使用容斥原理. 固定 $i$,考虑有多少个 $j \in [n]$ 满足 $\gcd(i, j) = \gcd(a_i, a_j) = 1$,将此数目记作 $f_i$.暂时不考虑 ...
- http2新特性
1.二进制分帧 http1.x是文本格式传输,http2二进制格式传输,并且被切分未过个帧发送,帧可以根据头部流标识重新组装. 2. 单一长连接 同一个域名使用一个TCP连接,(http1 ...