您的位置:首页 > 其它

ZOJ Monthly, August 2012

2012-08-26 17:46 441 查看
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 0x3fffffff
const 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|1
const 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;
}
/*
8
arrive FatSheep 3 4 7 5
arrive riversouther 2 4 1
share FatSheep riversouther
check FatSheep
arrive delta 2 10 4
check delta
share delta FatSheep
check 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: 太弱了,其他题目都没有做出来
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: