题目:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3633
题意:给你一个n个数字组成的串,同时有m个询问,问第a个数字和第b个数字之间是否存在相同的数,没有就输出"OK",存在就输出最右边出现的重复的数。
题解:线段树可以过,维护一个标志数组,flag[x]代表第x个段是否有重复的数,有重复的就是储存重复的数值,没有就存-1.对于一个区间,如果它的右子区间有重复的数,那它就等于它的右子区间,右子区间没有重复的数就是把左右区间合并起来找有没有重复的数,如果还没有那这个区间就等于它左子区间的值。
代码:
#include<cstdio> #include<cstring> #include<set> using namespace std; #define MAX 500005 int value[MAX]; int flag[MAX<<2];//-1代表没有重复的,正数代表右边开始第一个重复的 set<int> hashx; void push_up(int l,int r,int idx) { if(flag[idx<<1|1]!=-1) { flag[idx]=flag[idx<<1|1]; return; } hashx.clear(); int mid=(l+r)>>1; //从左子区间的最右边开始,在右子区间里查找有没有相同的 for(int i=mid+1;i<=r;++i) hashx.insert(value[i]); for(int i=mid;i>=l;--i) { if(hashx.count(value[i])==0) hashx.insert(value[i]); else { flag[idx]=value[i]; return; } } flag[idx]=flag[idx<<1]; return; } void build(int l,int r,int idx) { if(l==r) { flag[idx]=-1; return; } int mid=(l+r)>>1; build(l,mid,idx<<1); build(mid+1,r,idx<<1|1); push_up(l,r,idx); } int query(int a,int b,int l,int r,int idx) { if(a<=l&&r<=b) return flag[idx]; int mid=(l+r)>>1; int x,y; x=y=-1; if(b<=mid) return query(a,b,l,mid,idx<<1); if(mid<a) return query(a,b,mid+1,r,idx<<1|1); if(mid<b) y=query(a,b,mid+1,r,idx<<1|1); if(y!=-1) return y; hashx.clear(); for(int i=mid+1;i<=b;++i) hashx.insert(value[i]); for(int i=mid;i>=a;--i) { if(hashx.count(value[i])==0) hashx.insert(value[i]); else return value[i]; } return query(a,mid,l,mid,idx<<1); } int main() { int n,m,k; int a,b; for(;~scanf("%d",&n);) { for(int i=1;i<=n;++i) scanf("%d",value+i); build(1,n,1); scanf("%d",&m); for(;m--;) { scanf("%d%d",&a,&b); int ans=query(a,b,1,n,1); if(ans==-1) puts("OK"); else printf("%d\n",ans); } puts(""); } return 0; }
Cinema in Akiba
题意:告诉你第i个人买票的时候要买从左往右数空位中第j个空位,问你n个人分别买了哪个位置的票。
题解:线段树。维护区间内空座位数。
代码:
#include<cstdio> #include<cstring> using namespace std; #define MAX 50005 int summ[MAX<<2]; int indx[MAX]; void push_up(int idx) { summ[idx]=summ[idx<<1]+summ[idx<<1|1]; } void build(int l,int r,int idx) { summ[idx]=1; if(l==r) return; int mid=(l+r)>>1; build(l,mid,idx<<1); build(mid+1,r,idx<<1|1); push_up(idx); } int update(int x,int l,int r,int idx) { if(l==r) { summ[idx]=0; return l; } int mid=(l+r)>>1; int ans; if(x<=summ[idx<<1]) ans=update(x,l,mid,idx<<1); else ans=update(x-summ[idx<<1],mid+1,r,idx<<1|1); push_up(idx); return ans; } int main() { int n,m,k; for(;~scanf("%d",&n);) { build(1,n,1); for(int i=1;i<=n;++i) { scanf("%d",&k); indx[i]=update(k,1,n,1); } scanf("%d",&m); for(int i=1;i<=m;++i) { scanf("%d",&k); if(i==1) printf("%d",indx[k]); else printf(" %d",indx[k]); } puts(""); } return 0; }
题意:给你一些可选课程,同时给出课程的上课范围和该课程的学分,让你排一个能获得最大学分的课程表(课程时间不能冲突),问最大学分是多少。
题解:课程的时间范围给的有点变态啊,竟然是月日时分的,我是把这个换算成分钟为单位的值。这样题目就转换成给你一些一维线段和线段的权值,让你选出一些不重叠的线段,使得权值最大。这个果断的DP啊,就是状态不太好表示。我的方法首先按线段的右端点从小到大排序,dp[i]表示前i个线段的最大权值和,转移为dp[i]=max(max[i-1],dp[p[i]]+value[i]),p[i]为前i中与i不相交的线段的最大下标,这可以通过二分查找提前处理好。
代码:
#include<cstdio> #include<string> #include<map> #include<cstring> #include<algorithm> #include<ctype.h> #define max(a,b) ((a)>(b)?(a):(b)) #define MAX 100005 using namespace std; struct cla { int st,en; double cred; } stud[MAX]; int p[MAX]; double dp[MAX]; int n; bool cmp(const struct cla &a,const struct cla &b) { return a.en==b.en?(a.st<b.st):(a.en<b.en); } int binarySearch(int x) { int l=0,r=n-1,mid; if(x<stud[0].en) return -1; for(;l<r;) { mid=(l+r+1)>>1; if(stud[mid].en<=x) l=mid; else r=mid-1; } return l; } map<string,int> hashx; int monthtime[15]= {0,31,60,91,121,152,182,213,244,274,305,335,366}; int charToInt(char *c) { int num=0; for(int i=0; i<strlen(c)&&c[i]>='0'&&c[i]<='9'; ++i) num=(num*10)+c[i]-'0'; return num; } int main() { int a,b; int cnt,dayint; char month[25],day[25],time[25]; hashx.insert(make_pair("jan",0)); hashx.insert(make_pair("feb",1)); hashx.insert(make_pair("mar",2)); hashx.insert(make_pair("apr",3)); hashx.insert(make_pair("may",4)); hashx.insert(make_pair("jun",5)); hashx.insert(make_pair("jul",6)); hashx.insert(make_pair("aug",7)); hashx.insert(make_pair("sep",8)); hashx.insert(make_pair("oct",9)); hashx.insert(make_pair("nov",10)); hashx.insert(make_pair("dec",11)); for(; ~scanf("%d",&n);) { for(int i=0; i<n; ++i) { cnt=0; scanf("%s%s",month,day); scanf("%d:%d",&a,&b); scanf("%s",time); for(int j=0; j<strlen(month); ++j) month[j]=tolower(month[j]); dayint=charToInt(day); cnt+=((monthtime[hashx.find(string(month))->second]+dayint)*24*60+a*60+b); if(strcmp(time,"p.m.")==0) cnt+=(12*60); stud[i].st=cnt; cnt=0; scanf("%s%s",month,day); scanf("%d:%d",&a,&b); scanf("%s",time); for(int j=0; j<strlen(month); ++j) month[j]=tolower(month[j]); dayint=charToInt(day); cnt+=((monthtime[hashx.find(string(month))->second]+dayint)*24*60+a*60+b); if(strcmp(time,"p.m.")==0) cnt+=(12*60); stud[i].en=cnt+5; scanf("%lf",&stud[i].cred); } sort(stud,stud+n,cmp); int front=0; for(int i=0; i<=n; ++i) dp[i]=0; for(int i=0; i<n; ++i) p[i]=binarySearch(stud[i].st); dp[0]=stud[0].cred; double maxx=dp[0]; for(int i=1; i<n; ++i) { if(p[i]==-1) dp[i]=max(dp[i-1],stud[i].cred); else dp[i]=max(dp[i-1],dp[p[i]]+stud[i].cred); if(maxx<dp[i]) maxx=dp[i]; } printf("%.1f\n",maxx); } return 0; }
题意:看题目的提示就懂了。
题解:栈模拟。
代码:
#include<cstdio> #include<cstring> char m[512010],z[300],flag[512010]; int main() { int ans,top; for(;~scanf("%s%s",z,m);) { ans=0,top=1; int len=strlen(z); for(int i=0;m[i];++i) { flag[top-1]=m[i]; if(top>=len) { flag[top]=0; if(strcmp(flag+top-len,z)==0) { top-=len; ans++; } } top++; } printf("%d\n",ans); } return 0; }