2017-10-03清北模拟赛
T1 括号序列(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|是偶数。
1 /* 2 从左往右扫过来,遇到一个),观察之前有没有(, 3 如果有的话就抵消掉。 4 如果没有的话 -> 把这个字符变成( 操作数记为X 5 6 一直这么做,扫完整个字符串之后, 7 最终一定匹配完后剩下一堆左括号。 个数记为 Y 8 则ans=x+y/2 9 */ 10 #include <cstring> 11 #include <cstdio> 12 13 const int N(100005); 14 int n,top,ans; 15 char s[N]; 16 17 int Presist() 18 { 19 // freopen("bracket.in","r",stdin); 20 // freopen("bracket.out","w",stdout); 21 scanf("%s",s); n=strlen(s); 22 for(int i=0; i<n; ++i) 23 { 24 if(s[i]=='(') top++; //记录左括号个数(y值) 25 else 26 { 27 if(top<1) top++,ans++; 28 //没有左括号可与右括号匹配,将右括号变为左括号,累加x值 29 else top--; //抵消左括号和右括号 30 } 31 } 32 printf("%d\n",ans+top/2); 33 return 0; 34 } 35 36 int Aptal=Presist(); 37 int main(int argc,char*argv[]){;} 38 39 AC
T2 公交车(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。
1 #include <cstdio> 2 #include <vector> 3 #include <queue> 4 5 inline void read(int &x) 6 { 7 x=0; register char ch=getchar(); 8 for(; ch>'9'||ch<'0'; ) ch=getchar(); 9 for(; ch>='0'&&ch<='9'; ch=getchar()) x=x*10+ch-'0'; 10 } 11 const int N=20010; 12 int n,m,k,ans,sum[N]; 13 14 struct node 15 { 16 int to,val; 17 node() {} 18 node(int to,int val):to(to),val(val) {} 19 }; 20 std::vector<node> G[N]; 21 22 void DFS(int num,int s,int people) 23 { 24 if(num==n+1) 25 { 26 ans=s>ans?s:ans; 27 return; 28 } 29 people+=sum[num]; 30 sum[num]=0; 31 for(int i=0; i<G[num].size(); ++i) 32 { 33 int v=G[num][i].to; 34 int ps=G[num][i].val; 35 if(ps<=k-people) 36 { 37 sum[v]+=-ps; 38 DFS(num+1,s+ps,people+ps); 39 } 40 else if((people<k)&&(ps+people>k)) 41 { 42 sum[v]+=people-k; 43 DFS(num+1,s+k-people,k); 44 } 45 } 46 DFS(num+1,s,people); 47 return; 48 } 49 50 int Presist() 51 { 52 freopen("bus.in","r",stdin); 53 freopen("bus.out","w",stdout); 54 read(m); read(n); read(k); 55 for(int x,y,v,i=1; i<=m; ++i) 56 { 57 read(x); read(y); read(v); 58 G[x].push_back(node(y,v)); 59 } 60 DFS(1,0,0); 61 printf("%d\n",ans); 62 return 0; 63 } 64 65 int Aptal=Presist(); 66 int main(int argc,char*argv){;} 67 68 爆搜30分
1 /* 2 贪心做法 3 给怪兽以下车点为第一关键字排序、 4 每次让尽量多的怪兽上车 5 每一只怪兽上车时让上车时间尽量靠近前一个怪兽 6 f[]记录每个车上空间空出的时间 7 */ 8 #include <algorithm> 9 #include <cstdio> 10 11 inline void read(int &x) 12 { 13 x=0; register char ch=getchar(); 14 for(; ch>'9'||ch<'0'; ) ch=getchar(); 15 for(; ch>='0'&&ch<='9'; ch=getchar()) x=x*10+ch-'0'; 16 } 17 const int N(50005); 18 int k,n,c,ans,f[N]; 19 struct Cow { 20 int l,r,val; 21 bool operator < (const Cow &x)const 22 { 23 if(r==x.r) return l>x.l; 24 return r<x.r; 25 } 26 }node[N]; 27 28 int Presist() 29 { 30 read(k),read(n),read(c); 31 for(int i=1; i<=k; ++i) 32 read(node[i].l),read(node[i].r),read(node[i].val); 33 std:: sort(node+1,node+k+1); 34 for(int i=1,x,t; i<=k; ++i) 35 { 36 if(node[i].l<f[1]) continue; 37 for(x=1; x<=node[i].val&&x<=c&&node[i].l>=f[x]; ) 38 x++; x--; //减去多出node[i].val的哪一个怪兽 39 for(t=1; t<=c; ++t) 40 if(node[i].l<f[t]) break; 41 //t是第一个空出时间晚于当前怪兽上车时间的车位 42 t-=x; 43 for(; f[t+x]<=node[i].r&&t+x<=c; ) 44 f[t]=f[t+x],t++; //车位号向前更新 45 for(int j=1; j<=x; ++j) f[t++]=node[i].r; 46 ans+=x; 47 } 48 printf("%d\n",ans); 49 return 0; 50 } 51 52 int Aptal=Presist(); 53 int main(int argc,char**argv){;} 54 55 贪心 AC
1 /* 2 求这一群怪兽能过几只 3 维护一个f数组 f[i]表示i这个时刻 4 车上已经坐了几只怪兽了 5 [X,Y] Z 6 for (int i=X; i<Y; i++) 7 MAX=max(MAX,f[i]); 8 t=min(Z,M-MAX); 9 for (int i=X; i<Y; i++) f[i]+=t; 10 ans+=t 11 1.区间+ 2.区间查询最大值 12 线段树维护 klgn 13 */ 14 #include <cmath> 15 #include <cstdio> 16 #include <cstdlib> 17 #include <iostream> 18 #include <algorithm> 19 using namespace std; 20 int tree[65536][4],n,m,c,i,MIN,ans; 21 struct node 22 { 23 int x; 24 int y; 25 int z; 26 }; 27 node A[100005]; 28 int cmp(node i,node j) 29 { 30 return i.y<j.y; 31 } 32 void Update(int k) 33 { 34 tree[k*2][2]+=tree[k][3]; 35 tree[k*2+1][2]+=tree[k][3]; 36 tree[k*2][3]+=tree[k][3]; 37 tree[k*2+1][3]+=tree[k][3]; 38 tree[k][3]=0; 39 } 40 void work(int root,int l,int r,int k) 41 { 42 if (l==tree[root][0] && r==tree[root][1]) 43 { 44 tree[root][2]+=k; 45 tree[root][3]+=k; 46 return; 47 } 48 Update(root); 49 int mid=(tree[root][0]+tree[root][1])/2; 50 if (l<=mid) work(root*2,l,min(mid,r),k); 51 if (r>mid) work(root*2+1,max(mid+1,l),r,k); 52 tree[root][2]=min(tree[root*2][2],tree[root*2+1][2]); 53 } 54 int find(int root,int l,int r) 55 { 56 if (l==tree[root][0] && r==tree[root][1]) return tree[root][2]; 57 Update(root); 58 int mid=(tree[root][0]+tree[root][1])/2,p=453266144,q=453266144; 59 if (l<=mid) p=find(root*2,l,min(mid,r)); 60 if (r>mid) q=find(root*2+1,max(mid+1,l),r); 61 return min(p,q); 62 } 63 int main() 64 { 65 freopen("bus.in","r",stdin); 66 freopen("bus.out","w",stdout); 67 scanf("%d%d%d",&n,&m,&c); 68 for (i=32768; i<=65535; i++) tree[i][0]=tree[i][1]=i; 69 for (i=32767; i>=1; i--) 70 { 71 tree[i][0]=tree[i*2][0]; 72 tree[i][1]=tree[i*2+1][1]; 73 } 74 work(1,1+32767,m+32767,c); 75 for (i=1; i<=n; i++) 76 { 77 scanf("%d%d%d",&A[i].x,&A[i].y,&A[i].z); 78 A[i].y--; 79 } 80 sort(A+1,A+n+1,cmp); 81 for (i=1; i<=n; i++) 82 { 83 MIN=find(1,A[i].x+32767,A[i].y+32767); 84 if (MIN>A[i].z) 85 { 86 work(1,A[i].x+32767,A[i].y+32767,-A[i].z); 87 ans+=A[i].z; 88 } 89 else 90 { 91 work(1,A[i].x+32767,A[i].y+32767,-MIN); 92 ans+=MIN; 93 } 94 } 95 cout<<ans; 96 return 0; 97 }
T3 解谜游戏(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。
1 #include <cstring> 2 #include <cstdio> 3 4 #define min(a,b) (a<b?a:b) 5 #define max(a,b) (a>b?a:b) 6 #define LL long long 7 const int N(305); 8 int n,m,p,a[N][N]; 9 long long ans,tmp,sum[N][N]; 10 int change,min_[N][N][N]; 11 12 inline void violence() 13 { 14 /*40分做法 15 暴力枚举更改的点n^ 2 16 朴素的最大子矩阵n^2*m。 17 */ 18 for(int q=1; q<=n; ++q) 19 for(int h=1; h<=m; ++h) 20 { 21 for(int i=1; i<=n; ++i) 22 for(int j=1; j<=m; ++j) 23 sum[i][j]=a[i][j]; 24 sum[q][h]=max(sum[q][h],p); 25 for(int i=1; i<=n; ++i) 26 for(int j=1; j<=m; ++j) 27 sum[i][j]+=sum[i-1][j]; 28 for(int top=0; top<n; ++top) 29 for(int i=top+1; i<=n; ++i) 30 { 31 for(int j=1; j<=m; ++j) 32 { 33 if(tmp<0) tmp=(LL)sum[i][j]-sum[top][j]; 34 else tmp+=(LL)sum[i][j]-sum[top][j]; 35 ans=max(ans,tmp); 36 } tmp=0; 37 } 38 } 39 printf("%I64d\n",ans); 40 } 41 inline void WA() 42 { 43 /* 44 处理出每行的每段中的最小值、判断是否作为p被替换掉 45 但是WA掉了。。。 46 */ 47 for(int i=0; i<=n; ++i) 48 for(int j=0; j<=n; ++j) 49 for(int k=0; k<=m; ++k) 50 min_[i][j][k]=0x7fffffff; 51 for(int i=1; i<=n; ++i) 52 for(int j=1; j<=m; ++j) 53 { 54 min_[i-1][i][j]=a[i][j]; 55 sum[i][j]=sum[i-1][j]+a[i][j]; 56 } 57 for(int top=0; top<n; ++top) 58 for(int i=top+1; i<=n; ++i) 59 for(int j=1;j<=m; ++j) 60 min_[top][i][j]=min(min_[top][i][j],min_[top][i-1][j]); 61 for(int top=0; top<n; ++top) 62 for(int i=top+1; i<=n; ++i) 63 { 64 for(int j=1; j<=m; ++j) 65 { 66 change=min(change,min_[top][i][j]); 67 if(tmp-change+p<0) 68 change=0x7fffffff,tmp=(LL)sum[i][j]-sum[top][j]; 69 else tmp+=(LL)sum[i][j]-sum[top][j]; 70 ans=max(ans,tmp-change+p); 71 } tmp=0; change=0x7fffffff; 72 } 73 printf("%I64d\n",ans); 74 } 75 76 int Presist() 77 { 78 freopen("puzzle.in","r",stdin); 79 freopen("puzzle.out","w",stdout); 80 scanf("%d%d%d",&n,&m,&p); 81 for(int i=1; i<=n; ++i) 82 for(int j=1; j<=m; ++j) 83 scanf("%d",&a[i][j]); 84 if(n<=25&&m<=25) violence(); 85 else WA(); 86 return 0; 87 } 88 89 int Aptal=Presist(); 90 int main(int argc,char*argv[]){;}
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #define N 305 6 using namespace std; 7 int n,m,p,ans,d[N],s[N][N],minn[N],a[N][N],dp[N][N]; 8 int read() 9 { 10 int x=0,f=1; char ch=getchar(); 11 while(ch<'0'||ch>'9') {if(ch=='-')f=-1; ch=getchar();} 12 while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); 13 return x*f; 14 } 15 int main() 16 { 17 n=read(),m=read(),p=read(); 18 ans=-1000000000; 19 for(int i=1;i<=n;i++) 20 for(int j=1;j<=m;j++) 21 a[i][j]=read(),s[i][j]=s[i-1][j]+a[i][j];//预处理前缀和 22 for(int i=1;i<=n;i++)//枚举上边界 23 { 24 for(int j=1;j<=m;j++) minn[j]=a[i][j];//预处理每一列里的最小值 25 for(int j=i;j<=n;j++)//枚举下边界 26 { 27 for(int k=1;k<=m;k++) minn[k]=min(minn[k],a[j][k]);// 28 for(int k=1;k<=m;k++) d[k]=s[j][k]-s[i-1][k];//处理出在上边界与下边界围成的这个地方每一列的和 29 dp[0][1]=-1000000000; 30 for(int k=1;k<=m;k++) 31 { 32 dp[k][0]=max(dp[k-1][0]+d[k],d[k]); 33 dp[k][1]=max(max(dp[k-1][1]+d[k],d[k]-minn[k]+p),dp[k-1][0]+d[k]-minn[k]+p); 34 } 35 if(i==1&&j==n) ans=max(ans,dp[m][1]); 36 else ans=max(ans,max(dp[m][1],dp[m][0])); 37 for(int k=1;k<=m;k++) ans=max(ans,max(dp[k][1],dp[k][0])); 38 } 39 } 40 printf("%d",ans); 41 return 0; 42 } 43 44 AC