现在的位置: 首页 > 综合 > 正文

ZOJ Monthly, August 2012

2018年01月14日 ⁄ 综合 ⁄ 共 5336字 ⁄ 字号 评论关闭

Alice's
present

题目: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;
}

Education
Manage System

题意:给你一些可选课程,同时给出课程的上课范围和该课程的学分,让你排一个能获得最大学分的课程表(课程时间不能冲突),问最大学分是多少。
题解:课程的时间范围给的有点变态啊,竟然是月日时分的,我是把这个换算成分钟为单位的值。这样题目就转换成给你一些一维线段和线段的权值,让你选出一些不重叠的线段,使得权值最大。这个果断的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;
}

抱歉!评论已关闭.