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: 太弱了,其他题目都没有做出来
- ZOJ Monthly, August 2012
- ZOJ Monthly, August 2012
- ZOJ Monthly, August 2012 题解
- ZOJ Monthly, August 2012部分题目总结
- ZOJ Monthly, August 2014
- ZOJ Monthly, August 2014
- ZOJ Monthly, August 2012-A-ZOJ 3633 ZOJ 3635
- 135 - ZOJ Monthly, August 2014
- ZOJ Monthly, August 2014小记
- ZOJ Monthly, August 2012 - A Alice's present MAP函数
- ZOJ Monthly, August 2011 zoj 3528
- ZOJ Monthly, August 2011 zoj 3520
- ZOJ Monthly, August 2011 zoj 3523
- 135 - ZOJ Monthly, August 2014 - HMachine
- 浙大月赛ZOJ Monthly, August 2014
- zoj 3805 Machine(ZOJ Monthly, August 2014 - H)
- zoj 3798 Abs Problem( ZOJ Monthly, August 2014 - A)
- ZOJ Monthly, August 2012 - C Cinema in Akiba 树状数组+二分
- (98)Address already in use: make_sock: could not bind to address 0.0.0.0:80
- PowerPCB(PADS)常见问题全集
- Oracle基于Cancel的不完全恢复
- Oracle基于时间的不完全恢复
- MySQL 全文搜索笔记
- ZOJ Monthly, August 2012
- Oracle全备后的恢复(Windows系统)
- Oracle恢复实验(一)
- Oracle恢复实验(二)
- 《深入理解java虚拟机》学习笔记6——类加载机制
- Oracle恢复实验(三)
- Oracle恢复实验(四)
- u-boot-2012-07移植三
- 目录文件读取