ZOJ Monthly, August 2012

来源:互联网 发布:淘宝网集市店铺 编辑:程序博客网 时间:2024/05/21 10:58

http://acm.zju.edu.cn/onlinejudge/showContestProblems.do?contestId=340



A Alice's present   题意:给出一个10^5 的数组,5w次询问,每次询问给出一段区间 [ l ,r ] 要求判断区间里的每个数是否只是出现了一次,如果是输出OK,否则输出从右 向左第一个出现两次的数

   思路: 我是用线段树离线查询做的,感觉单调栈也可以做得样子,而且代码应该短很多

#include <cstdlib>#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>using namespace std;#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1#define inf 0x3fffffffconst int maxn=500010;int d[maxn<<2],first[maxn],a[maxn],tab[maxn];struct Node{    int l,r,id;}q[50010];int cmp(Node a,Node b){    return a.l > b.l;}void build(int l,int r,int rt){    d[rt]=inf;    if(l==r) return;    int m=(l+r)>>1;    build(lson);    build(rson);}void update(int p,int val,int l,int r,int rt){    if(l==r){       d[rt]=val;return;    }    int m=(l+r)>>1;    if(p<=m) update(p,val,lson);    else update(p,val,rson);    d[rt]=min(d[rt<<1],d[rt<<1|1]);}int query(int L,int R,int val,int l,int r,int rt){    if(d[rt]>val) return -1;    if(l==r) return l;    int m=(l+r)>>1;    if(R<=m) return query(L,R,val,lson);    if(L>m)  return query(L,R,val,rson);    int ret2=query(m+1,R,val,rson);    if(ret2!=-1) return ret2;    return  query(L,m,val,lson);;}int bin(int key,int l,int r){    while(l<=r)    {        int m=(l+r)>>1;        if(tab[m]==key) return m;        else if(tab[m]>key) r=m-1;        else l=m+1;    }}int ans[maxn];int main(){    int n,m;    while(scanf("%d",&n)==1)    {        build(1,n,1);        for(int i=1;i<=n;i++)  scanf("%d",&a[i]),tab[i-1]=a[i];        sort(tab,tab+n);        int k=unique(tab,tab+n)-tab-1;        scanf("%d",&m);        for(int i=0;i<m;i++)           scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;        sort(q,q+m,cmp);        memset(first,-1,sizeof(first));        int dd=0;        for(int i=n;i>=1;i--)        {             int pos=bin(a[i],0,k);             //cout<<a[i]<<" "<<pos<<endl;             if(first[pos]==-1) first[pos]=i;             else update(i,first[pos],1,n,1),first[pos]=i;             while(dd<m&&q[dd].l==i)             {                //cout<<q[dd].l<<" "<<q[dd].r<<" ";                int p=query(q[dd].l,q[dd].r,q[dd].r,1,n,1);                ans[q[dd].id]= (p==-1)?-1:a[p];                dd++;             }            if(dd>=m) break;        }        for(int i=0;i<m;i++)          if(ans[i]!=-1) printf("%d\n",ans[i]);          else puts("OK");        puts("");    }    return 0;}

C Cinema in Akiba 题, 线段树水题,因为输出错误害了我wa两次,无语……

#include <cstdlib>#include <iostream>#include <cstring>#include <cstdio>using namespace std;#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1const int maxn=500010;int d[maxn<<2];void build(int l,int r,int rt){    d[rt]=r-l+1;    if(l==r) return;    int m=(l+r)>>1;    build(lson);    build(rson);}int update(int p,int l,int r,int rt){    if(l==r){      d[rt]=0;return l;    }    int m=(l+r)>>1,ret;    if(p<=d[rt<<1]) ret=update(p,lson);    else ret=update(p-d[rt<<1],rson);    d[rt]=d[rt<<1]+d[rt<<1|1];    return ret;}int ans[maxn];int main(){    int n,m,a;    while(scanf("%d",&n)==1)    {        build(1,n,1);        for(int i=1;i<=n;i++)        {             scanf("%d",&a);             ans[i]=update(a,1,n,1);             //cout<<ans[i]<<endl;        }        scanf("%d",&m);        for(int i=0;i<m;i++)        {            scanf("%d",&a);            if(i)putchar(' ');            printf("%d",ans[a]);        }        puts("");    }    return 0;}

I Information Sharing Information Sharing  题意: 给出最多10w个孩子,每个孩子之间可以分享自己知道的信息,每个孩子知道的信息最多为10,信息的种类不超过1000,然后问经过一系列的之后查询某个孩子知道的信息种类数

   思路: 我是用并查集做的,每个孩子都有一个集合表示该孩子知道的信息量,但是信息的种类最多是1000,孩子个数是10w,直接开数组的是开不下的,所以我用到STL的容器,把每个不是根节点的内存及时的销毁……其他的就是并查集的找父亲节点和合并两个集合就可以了

#include <cstdlib>#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>#include <vector>#include <map>using namespace std;const int maxn=100010;int fa[maxn];vector<int> set[maxn];map<string,int> mp;bool flag[maxn];int find(int a){    while(fa[a]!=-1) a=fa[a];    return a;}void Union(int u,int v){    int f1=find(u),f2=find(v);    if(f1==f2) return;    int sz=set[f2].size();    for(int i=0;i<sz;i++) set[f1].push_back(set[f2][i]);    sort(set[f1].begin(),set[f1].end());    set[f1].resize(unique(set[f1].begin(),set[f1].end())-set[f1].begin());    set[f2].clear();    fa[f2]=f1;}int main(){    int n,m,k,a,dd;    char ord[20],name1[20],name2[20];    while(scanf("%d",&n)==1)    {        dd=1;        memset(fa,-1,sizeof(fa));        for(int i=0;i<n;i++)        {            scanf("%s",ord);            if(ord[0]=='a')            {                scanf("%s",name1);                scanf("%d",&k);                mp[name1]=dd;                set[dd].clear();                for(int j=1;j<=k;j++) scanf("%d",&a),set[dd].push_back(a);                dd++;            }            else if(ord[0]=='s')            {                 scanf("%s %s",name1,name2);                 int u=mp[name1],v=mp[name2];                 Union(u,v);            }            else            {                scanf("%s",name1);                int f1=find(mp[name1]);                printf("%d\n",set[f1].size());            }        }        mp.clear();    }    return 0;}/*8arrive FatSheep 3 4 7 5arrive riversouther 2 4 1share FatSheep riversouthercheck FatSheeparrive delta 2 10 4check deltashare delta FatSheepcheck riversouther*/

J题  Just Another Information Sharing Problem网络流,从源点 向每个孩子建 边 ,流量为该孩子能分享信息的最大值 ,每个孩子向自己知道的信息建流量为 1 的边,每个信息向汇点建流量为1的边,最大流即可;

   tick 就是 还要把m每个知道的信息 要和源点建流量为1的边,不然会wa。 代码太戳,就不贴了

K题 Keep Deleting  做得比较爽的一题,30分钟1Y。 思路就是kmp,然后建一个栈,栈里放着没有被删除的字符,从左向右扫描

#include <cstdlib>#include <iostream>#include <cstring>#include <cstdio>using namespace std;const int maxn=555555;char s[maxn],a[300],stack[maxn];int next[300],len;void get_next(){    next[0]=-1;    int i=0,j=-1;    while(i<len)    {        if(j==-1||a[i]==a[j]) next[++i]=++j;        else j=next[j];    }}int local(int top,char c){    if(top==0) return (s[0]==c)?0:-1;    int i=stack[top-1]+1;    while(i!=-1&&a[i]!=c) i=next[i];    return i;}int solve(){    int L=strlen(s),top=0,ret=0;    for(int i=0;i<L;i++)    {        int pos=local(top,s[i]);        if(pos>=len-1) top-=(len-1),ret++;        else stack[top++]=pos;        //cout<<s[i]<<"  "<<top<<": "<<pos<<endl;    }    return ret;}int main(int argc, char *argv[]){    while(scanf("%s%s",a,s)==2)    {        len=strlen(a);        get_next();      /*  for(int i=0;i<len;i++)          cout<<next[i]<<" ";        cout<<endl;*/        printf("%d\n",solve());    }    return 0;}

PS: 太弱了,其他题目都没有做出来

原创粉丝点击