contest 15
来源:互联网 发布:mix2 知乎 编辑:程序博客网 时间:2024/05/17 22:02
比赛链接
比赛中解决的问题
A
Problem description
给定两个一次函数,求相等时最小的值
Data Limit:n <= 100 Time Limit: 1s
Solution
暴力求出所有符合的数,或者用数学整除直接算出,注意小于的情况
Code
if(d>b){swap(b,d),swap(a,c);} for(int i=0;i<=500000;i++) if((a*i+b-d==0)||(a*i+b-d)%c==0) {cout<<a*i+b<<"\n";return 0;} cout<<"-1\n";
B
Problem description
给定一个数列,求之中是否存在至少一对相反数
Data Limit:n <= 1e4 Time Limit: 2s
Solution
我们用两个数组分别记录positive 和negative ,注意要两个数组,一个会出乱子,然后看这个位置对应的数组是不是1。注意memset
Code
for(int i=1;i<=m;i++) { int ok=0,k,t1; memset(book1,0,sizeof(book1)); memset(book2,0,sizeof(book2)); cin>>k; for(int i=1;i<=k;i++) { cin>>t1; if(t1<0) book1[0-t1]=1; else book2[t1]=1; } for(int i=1;i<=20000;i++) if(book1[i]&book2[i])ok=1; if(!ok) {puts("YES");return 0;} } puts("NO");
赛后补题
C
Problem description
给定两个集合,每一个集合对应的是该人可以移动的步数,怪物起始可以在任意点,到达1就获胜,两个人都足够聪明,求怪物起始以及谁先手的胜负情况
Data Limit:n <= 1e4 Time Limit: 4s
Solution
我们用记忆化搜索,当且仅当一个点的所有情况是必败态,他的后继是必胜态,于是我们枚举所有的情况就可以了
Code
void dfs(int now,int p){ if(f[p][now]) return ; f[p][now]=2; if(now==0) return ; for(int i=0;i<k[!p];i++) { int lat=(now-v[!p][i]+n)%n; Orz_He_Xv[!p][lat]++; if(Orz_He_Xv[!p][lat]==k[!p]) { f[!p][lat]=1; for(int kk=0;kk<k[p];kk++) dfs((lat-v[p][kk]+n)%n,p); } }}
D
Problem description
给定一个图,有三类边 u->v u->[l,r],[l,r]->v每一条边都有权值,求单源最短路
Data Limit:n <= 1e5 Time Limit: 2s
Solution
首先我们要处理区间边的情况,我们建造两颗线段树(有shenben说一颗也可以),然后对应线段树上的区间连边,比如你要连的区间为[1,3]那么你分别向[1,2] [3,3]连边,然后跑一边dij+堆的最短路就可以了
Code
void build(int l,int r,int rt){ if(l==r) { tr[rt][0]=tr[rt][1]=l; return ; } tr[rt][0]=++tot; tr[rt][1]=++tot; build(l,mid,ls),build(mid+1,r,rs); add(tr[rt][0],tr[ls][0],0),add(tr[rt][0],tr[rs][0],0); add(tr[ls][1],tr[rt][1],0),add(tr[rs][1],tr[rt][1],0);}void update(int l,int r,int rt,int from,int L,int R,int W,int t){ if(L<=l&&r<=R) { if(t==2) add(from,tr[rt][0],W); else if(t==3) add(tr[rt][1],from,W); return ; } if(L<=mid) update(l,mid,ls,from,L,R,W,t); if(R>mid) update(mid+1,r,rs,from,L,R,W,t); return ;}void dij(){ priority_queue<Node> q; memset(dis,38,sizeof(dis)); inf =dis[0]; dis[s]=0; q.push((Node){s,0}); while(!q.empty()) { Node x=q.top();q.pop(); if(book[x.p]) continue; book[x.p]=1; for(int i=head[x.p];i;i=e[i].nxt) { if(dis[e[i].to]>x.w+e[i].w) { dis[e[i].to]=x.w+e[i].w; q.push((Node){e[i].to,dis[e[i].to]}); } } }}
Ps: dij的continue的部分我写成了return 然后被坑了好久
E
Problem description
给定颜色序列,求分成最小的连续区间,使得区间内的元素的颜色的种类小于k(1<=k<=n)
Data Limit:n <= 1e5 Time Limit: 2s
Solution
我的是暴力做法,我们通过实践可以发现,如果存在一个l,r,他们的答案是相同的,那么他们之间的答案也是相同的,我们就可以进行二分区间然后暴力求解啦//
正解貌似是主席树(???)//
-----------------------------
update
这里再说一种线段树的方法,我们用线段树的叶节点维护一段1~n的区间,表示这里的颜色的数目,然后我们在树上二分//
初始化:我们用一个vector数组记录这个节点可以用的k的值//
二分每一次贪心,如果可以走右边尽量走右边//
建树:存最小值,至于为什么下面会证明//
------------
反证法,如果存最大值得话,当一个值等于左子树的时候我们是不能区分到底是向左还是向右的,因为有可能右边的最左边也有可能和他相等,//
但是我们用贪心的思想的话这样值不满足的。//
证毕
### 在Code的下面会有第二个代码的完整实现
update
好像还有一种树状数组的方法??
update
线段树的做法其实和树状数组的思想是一样的,但是树状数组常数比较小,并且空间小,所以比较优//
简单分析一下,就是把线段树的部分替换成了树状数组。//
不同之处:二分的时候不同,线段树是建立一些虚拟的节点以便于树上二分,而树状数组的定义就是一部分的前缀和,所以可以直接二分。//
更新不同,用拆分的思想更新//
注意点,二分是二分二进制上的0和1,然后每一次二分的点是右区间的左端点。//
总而言之,线段树的思想还是非常巧妙的啦//
--------
由于不能换行,于是我用//表示换行了,这样思路清晰一些
Code
暴力出奇迹
inline int get(int x){ memset(col,0,sizeof(col)); int cnt=0,ans=1; for(int i=1;i<=n;i++) { if(col[a[i]]==ans) continue; cnt++; col[a[i]]=ans; if(cnt>x) {ans++;cnt=1;col[a[i]]=ans;} } return ans;}void solve(int l,int r){ if(l>r) return ; ans[l]=get(l),ans[r]=get(r); if(ans[l]==ans[r]) { for(int i=l+1;i<=r-1;i++) ans[i]=ans[l]; return ; } int mid=l+(r-l)/2; solve(l+1,mid),solve(mid,r-1); return ;}
线段树
#include<bits/stdc++.h>#define next NxTe#define ls (rt<<1)#define rs (rt<<1|1)#define mid (l+(r-l)/2)#define maxn 200000using namespace std;int tag[maxn<<4],tr[maxn<<4],a[maxn],head[maxn],next[maxn],ans[maxn];int n,m;vector<int> v[maxn];void pushdown(int rt){ tag[ls]+=tag[rt],tag[rs]+=tag[rt]; tr[ls]+=tag[rt],tr[rs]+=tag[rt]; tag[rt]=0; return ;}void update(int l,int r,int rt,int L,int R,int C){ if(L<=l&&r<=R) {tr[rt]+=C,tag[rt]+=C;return ;} if(tag[rt]) pushdown(rt); if(L<=mid) update(l,mid,ls,L,R,C); if(R>mid) update(mid+1,r,rs,L,R,C); tr[rt]=min(tr[ls],tr[rs]); return ;}int find(int l,int r,int rt,int x){ if(l==r) return l;//返回的是地址 if(tag[rt]) pushdown(rt); if(tr[rs]<=x) return find(mid+1,r,rs,x);//右子树满足先选右子树咯 else return find(l,mid,ls,x);}int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]),head[i]=next[i]=n+1,v[1].push_back(i); for(int i=n;i>=1;i--) next[i]=head[a[i]],head[a[i]]=i; for(int i=1;i<=n;i++) if(head[i]<=n) update(1,n,1,head[i],n,1); int x,y; for(int i=1;i<=n;i++) { for(int j=0;j<v[i].size();j++) { x=v[i][j]; y=find(1,n,1,x)+1; v[y].push_back(x); ans[x]++; } update(1,n,1,i,next[i]-1,-1); } for(int i=1;i<=n;i++) printf("%d ",ans[i]); return 0;}
树状数组
#include<bits/stdc++.h>#define lowbit(k) (k&(-k))#define maxn 200000using namespace std;int tr[maxn],next[maxn],head[maxn],ans[maxn],a[maxn];vector<int> v[maxn];int n;void update(int x,int up){ while(x<=n) { tr[x]+=up; x+=lowbit(x); } return ;}int find(int x){ int u=0; for(int i=16;i>=0;i--) { if((u|(1<<i))>n) continue; if(tr[u|(1<<i)]<=x) u|=(1<<i),x-=tr[u]; } return u;}int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]),next[i]=head[i]=n+1; for(int i=n;i>=1;i--) next[i]=head[a[i]],head[a[i]]=i; for(int i=1;i<=n;i++) if(head[i]<=n) update(head[i],1); for(int i=1;i<=n;i++) v[1].push_back(i); for(int i=1;i<=n;i++) { for(int j=0;j<v[i].size();j++) { int x=v[i][j]; v[find(x)+1].push_back(x); ans[x]++; } update(i,-1),update(next[i],1); } for(int i=1;i<=n;i++) printf("%d ",ans[i]); return 0;}
- contest 15
- Contest
- The 15th Zhejiang University Programming Contest
- The 15th Zhejiang University Programming Contest
- The 15th Zhejiang University Programming Contest
- The 15th Zhejiang University Programming Contest
- 2017.5.15 COCI2011/2012 Contest#5
- WHU 2013 Summer Team Contest #15 - SWERC 2011[xioumu]
- Beauty Contest(2013.09.15)(凸包)
- 2015-2016 ACM-ICPC Northeastern European Regional Contest (NEERC 15)
- The 15th UESTC Programming Contest Final 总结
- Contest Scoreboard
- following contest
- Beauty Contest
- Harmonious Contest
- Harmonious Contest
- Cow Contest
- Cow Contest
- Java源码阅读之ArrayList
- 建图最短路同余(luogu2662 vijos1054 xjoi2157)(bzoj2118)
- 左偏树
- 欧拉函数性质证明 : n所有约数的欧拉函数和等于n
- 冒泡排序法(Bubble Sorting)
- contest 15
- 为什么要来写博客
- 计算几何基础模板 以后还会更新
- 判断直线相交思维好题 (poj1039)
- 莫比乌斯反演学习之路~
- border-radius属性详解
- VPP初始化
- AC自动机+dp(CodeForces
- OI小结