[题解]CodeChef JUNE Challenge 17
来源:互联网 发布:金十数据如何看原油 编辑:程序博客网 时间:2024/06/05 06:42
这次比赛打的很有趣啊。
Challenge大战!
A Good Set
题意简述
定义“好集合”为:集合中元素两两不同,权值均在
输出大小为
数据范围
思路
一开始想二进制之类的balabala……
最后发现输出最大的前
Naive!
代码
#include<bits/stdc++.h> using namespace std; template<typename T> void read(T &x) { char ch=getchar(); for (x=0;ch<'0'||ch>'9';ch=getchar()); for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar()); } int T,n; int main() { read(T); while (T--) { read(n); for (int i=1;i<=n;i++) printf("%d%c",501-i," \n"[i==n]); } return 0; }
Xenny and Coin Rankings
题意简述
给二维坐标定义了一个序。
大体图形是这样子的:
然后问你一个矩形范围内标号最大的点是多少。
数据范围
思路
标号最大的肯定是右上角的啊…
公式题。
代码
#include<bits/stdc++.h> using namespace std; template<typename T> void read(T &x) { char ch=getchar(); for (x=0;ch<'0'||ch>'9';ch=getchar()); for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar()); } typedef long long ll; int T,u,v,x; ll ans; int main() { read(T); while (T--) { read(u),read(v); x=u+v; ans=1LL*(1+x)*x/2; ans+=u+1; printf("%lld\n",ans); } return 0; }
Chef and the Feast
题意简述
每次吃,假设吃掉
最大化幸福度之和。
数据范围
思路
贪心。
一开始想的正的都在一起选,负的一个一个选。
wawawawawa。
后来撕烤了一下。
猜了个结论:一起选的一定是从大到小连续的一段区间,剩下的单独选。
排序,从大到小选,如果加上这盘菜还能使答案
正确性证明见wa爷爷blog:http://wronganswer.blog.uoj.ac/blog/2667
代码
#include<bits/stdc++.h> using namespace std; template<typename T> void read(T &x) { char ch=getchar(); int f=1; for (x=0;ch!='-'&&(ch<'0'||ch>'9');ch=getchar()); if (ch=='-') f=-1,ch=getchar(); for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar()); x*=f; } typedef long long ll; int T,n; int seq[100010]; ll u,sum,ans,size; int main() { read(T); while (T--) { read(n); for (int i=1;i<=n;i++) read(seq[i]); sort(seq+1,seq+n+1); sum=0,ans=0,size=0; for (int i=n;i>=1;i--) if (seq[i]*size+sum >=0) sum+=seq[i],size++; else { for (int j=i;j>=1;j--) ans+=seq[j]; break; } ans+=sum*size; printf("%lld\n",ans); } return 0; }
Pairwise union of sets
题意简述
给你
每个集合的元素
问有多少对集合,它们的并集为
数据范围
思路
看到题第一感随手打了个bitset…
TLE……
加了个优化,如果两个集合的size之和都到不了
TLE……
随眼一瞟看到元素个数之和
按照
然后就A了……
然后就过了……
代码
#include<bits/stdc++.h> using namespace std; template<typename T> void read(T &x) { char ch=getchar(); for (x=0;ch<'0'||ch>'9';ch=getchar()); for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar()); } int T,n,k,ans,u,v; int num[2510]; void work1000() { bitset<2510> B[2510]; for (int i=1;i<=n;i++) B[i].reset(); memset(num,0,sizeof(num)); for (int i=1;i<=n;i++) { read(u); for (int j=1;j<=u;j++) { read(v); B[i].set(v); num[i]++; } } ans=0; for (int i=1;i<=n;i++) for (int j=i+1;j<=n;j++) if (num[i]+num[j]>=k && (B[i]|B[j]).count()==k) ans++; printf("%d\n",ans); } void work100() { bitset<110> B[2510]; for (int i=1;i<=n;i++) B[i].reset(); memset(num,0,sizeof(num)); for (int i=1;i<=n;i++) { read(u); for (int j=1;j<=u;j++) { read(v); B[i].set(v); num[i]++; } } ans=0; for (int i=1;i<=n;i++) for (int j=i+1;j<=n;j++) if (num[i]+num[j]>=k && (B[i]|B[j]).count()==k) ans++; printf("%d\n",ans); } int main() { read(T); while (T--) { read(n),read(k); if (k<=100) work100(); else work1000(); } return 0; }
Triplets
题意简述
给定三个序列
求
数据范围
思路
two pointers。
都排序之后枚举
代码
#include<bits/stdc++.h> using namespace std; template<typename T> void read(T &x) { char ch=getchar(); for (x=0;ch<'0'||ch>'9';ch=getchar()); for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar()); } typedef long long ll; #define MAXN 100010 const int mo=1000000007; int T,a,b,c; int A[MAXN],B[MAXN],C[MAXN]; ll suma,sumc,ans; int main() { read(T); while (T--) { read(a),read(b),read(c); for (int i=1;i<=a;i++) read(A[i]); for (int i=1;i<=b;i++) read(B[i]); for (int i=1;i<=c;i++) read(C[i]); sort(A+1,A+a+1); sort(B+1,B+b+1); sort(C+1,C+c+1); suma=0,sumc=0,ans=0; for (int i=1,j=1,k=1;j<=b;j++) { while (i<=a && A[i]<=B[j]) suma=(suma+A[i++])%mo; while (k<=c && C[k]<=B[j]) sumc=(sumc+C[k++])%mo; ans=(ans+1LL*(i-1)*(k-1)%mo*B[j]%mo*B[j] + suma*(k-1)%mo*B[j] + sumc*(i-1)%mo*B[j] + suma*sumc)%mo; } printf("%lld\n",ans); } return 0; }
Chef and Prime Queries
题意简述
给出长度为
设
每次询问
数据范围
思路
稍微转化一下就会发现这是一个矩形和问题。
离线询问,将每个询问拆成
排序。顺序扫描
质因子个数
总复杂度
代码
#include<bits/stdc++.h>using namespace std;template<typename T>void read(T &x){ char ch=getchar(); for (x=0;ch<'0'||ch>'9';ch=getchar()); for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar());}int n,q,t1,t2,t3,t4,Q_cnt,now,tmp;int a[100010],ans[100010];int p_cnt,prime[100010],mn[1000010],go[1000010],ti[1000010],idx[1000010];bool not_p[1000010];void sieve(int n){ not_p[1]=1; for (int i=2;i<=n;i++) { if (!not_p[i]) { prime[++p_cnt]=i; mn[i]=p_cnt; go[i]=1; ti[i]=1; } for (int j=1;i*prime[j]<=n && j<=p_cnt;j++) { not_p[i*prime[j]]=1; if (i%prime[j]==0) { mn[i*prime[j]]=mn[i]; go[i*prime[j]]=go[i]; ti[i*prime[j]]=ti[i]+1; break; } mn[i*prime[j]]=j; go[i*prime[j]]=i; ti[i*prime[j]]=1; } } p_cnt=0; for (int i=1;i<=n;i++) { if (!not_p[i]) p_cnt++; idx[i]=p_cnt; }}struct BIT{ static const int size=100000; int d[100010]; BIT() { memset(d,0,sizeof(d)); } int lowbit(int x) { return x&(-x); } void modify(int pos,int val) { for (;pos<=size;pos+=lowbit(pos)) d[pos]+=val; } int query(int l,int r) { int ret=0; for (;r;r-=lowbit(r)) ret+=d[r]; for (;l;l-=lowbit(l)) ret-=d[l]; return ret; }}T;struct Query{ int pos,x,y,ty,id; Query(int _pos=0,int _x=0,int _y=0,int _ty=0,int _id=0) { pos=_pos,x=_x,y=_y,ty=_ty,id=_id; } bool operator < (const Query &n1) const { return pos<n1.pos; } void print() { printf("pos=%d,[%d,%d],id=%d\n",pos*ty,x,y,id); }}Q[200010];int main(){ sieve(1000000); read(n); for (int i=1;i<=n;i++) read(a[i]); read(q); for (int i=1;i<=q;i++) { read(t1),read(t2),read(t3),read(t4); Q[++Q_cnt]=Query(t1-1,idx[t3-1],idx[t4],-1,i); Q[++Q_cnt]=Query(t2,idx[t3-1],idx[t4],1,i); } sort(Q+1,Q+Q_cnt+1); now=1; for (int i=1;i<=Q_cnt;i++) { while (now<=Q[i].pos) { tmp=a[now]; while (tmp!=1) { T.modify(mn[tmp],ti[tmp]); tmp=go[tmp]; } now++; } ans[Q[i].id]+=Q[i].ty*T.query(Q[i].x,Q[i].y); } for (int i=1;i<=q;i++) printf("%d\n",ans[i]); return 0;}
Cloning
题意简述
定义两个长度相等的子串是“相似的”:将它们的元素分别排序后,一一对应,最多只有一位不同。
给出长度为
每次询问两个长度相等子串是否是相似的。
数据范围
思路
hash+主席树。
按照权值哈希,权值为
在主席树上,两个区间一起跑,找到哈希相同的最大前缀和最大后缀。
判断一下即可。
代码
#include<bits/stdc++.h> using namespace std; template<typename T> void read(T &x) { char ch=getchar(); for (x=0;ch<'0'||ch>'9';ch=getchar()); for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar()); } #define MAXN 100010 #define MAXV 100000 typedef unsigned long long ull; const ull base=13331; ull basepow[MAXN],val1,val2; int T,n,q,l1,r1,l2,r2,posl,posr; int seq[MAXN]; namespace PT { struct Node{ Node *ch[2]; ull sum; void pushup() { sum=ch[0]->sum+ch[1]->sum; } }*null=new Node; Node pool[MAXN*30]; Node *tail=pool; Node *NewNode() { Node *p=tail++; p->ch[0]=p->ch[1]=null; p->sum=0; return p; } Node *Root[MAXN]; void init() { null->ch[0]=null->ch[1]=null; null->sum=0; tail=pool; for (int i=0;i<=n;i++) Root[i]=NewNode(); } void add(int pos,int l,int r,Node *node,Node *pre) { if (l==r) { node->sum=pre->sum+basepow[pos]; return; } int mid=(l+r)>>1; if (pos<=mid) { if (node->ch[0]==null) node->ch[0]=NewNode(); node->ch[1]=pre->ch[1]; add(pos,l,mid,node->ch[0],pre->ch[0]); } else { if (node->ch[1]==null) node->ch[1]=NewNode(); node->ch[0]=pre->ch[0]; add(pos,mid+1,r,node->ch[1],pre->ch[1]); } node->pushup(); } int queryl(int l,int r,Node *l1,Node *r1,Node *l2,Node *r2) { if (l==r) return l; int mid=(l+r)>>1; if (r1->ch[0]->sum - l1->ch[0]->sum != r2->ch[0]->sum - l2->ch[0]->sum) return queryl(l,mid,l1->ch[0],r1->ch[0],l2->ch[0],r2->ch[0]); else return queryl(mid+1,r,l1->ch[1],r1->ch[1],l2->ch[1],r2->ch[1]); } int queryr(int l,int r,Node *l1,Node *r1,Node *l2,Node *r2) { if (l==r) return l; int mid=(l+r)>>1; if (r1->ch[1]->sum - l1->ch[1]->sum != r2->ch[1]->sum - l2->ch[1]->sum) return queryr(mid+1,r,l1->ch[1],r1->ch[1],l2->ch[1],r2->ch[1]); else return queryr(l,mid,l1->ch[0],r1->ch[0],l2->ch[0],r2->ch[0]); } ull judge(int L,int R,int l,int r,Node *l1,Node *r1,Node *l2,Node *r2) { if (R<l || r<L) return 0; if (L<=l && r<=R) return r1->sum - l1->sum + r2->sum - l2->sum; int mid=(l+r)>>1; return judge(L,R,l,mid,l1->ch[0],r1->ch[0],l2->ch[0],r2->ch[0])+judge(L,R,mid+1,r,l1->ch[1],r1->ch[1],l2->ch[1],r2->ch[1]); } } int main() { basepow[0]=1; for (int i=1;i<=100000;i++) basepow[i]=basepow[i-1]*base; read(T); while (T--) { read(n),read(q); PT::init(); for (int i=1;i<=n;i++) { read(seq[i]); PT::add(seq[i],1,MAXV,PT::Root[i],PT::Root[i-1]); } for (int i=1;i<=q;i++) { read(l1),read(r1),read(l2),read(r2); val1=PT::Root[r1]->sum - PT::Root[l1-1]->sum; val2=PT::Root[r2]->sum - PT::Root[l2-1]->sum; if (val1==val2) puts("YES"); else { posl=PT::queryl(1,MAXV,PT::Root[l1-1],PT::Root[r1],PT::Root[l2-1],PT::Root[r2]); posr=PT::queryr(1,MAXV,PT::Root[l1-1],PT::Root[r1],PT::Root[l2-1],PT::Root[r2]); if ((posl+1>posr-1 || judge(posl+1,posr-1,1,MAXV,PT::Root[l1-1],PT::Root[r1],PT::Root[l2-1],PT::Root[r2])==0) && (val1+basepow[posl]==val2+basepow[posr] || val1+basepow[posr]==val2+basepow[posl])) puts("YES"); else puts("NO"); } } } return 0; }
Euler Sum
题意简述
求
数据范围
代码长度限制1KB = =(真的大丈夫?
思路
首先语言肯定选个自带高精度的…现学了一下PY…
然后应该用什么算法呢…找了半天e的性质无果…
忘了墩爷还是YJQ随口一句类欧几里得…好嘛…现学一下类欧。
类欧好像有两种形式,一种是分数型
另一种是一般型
然后我就xjb用泰勒展开强行把
考后想了下可不可以用
吐槽一下PY还限制递归深度……
代码
import sys sys.setrecursionlimit(1000000000) def solve(A,B,C,n): if (A==0): return (n+1)*(B//C) if (A>=C): return solve(A%C,B,C,n)+n*(n+1)//2*(A//C) if (B>=C): return solve(A,B%C,C,n)+(n+1)*(B//C) m=(A*n+B)//C return n*m-solve(C,C-B-1,A,m-1) n=int(input()) C=1 A=1 lim=3000 for i in range (1,lim): C*=i for i in range (1,lim): A=(A*i)+1 print(solve(A,0,C,n))
Persistent oak
题意简述
给你一棵树,树上每个节点都有一个重量承受度
当其子树的重量之和
有两个操作:
1.某个节点长出了重量为
2.询问一棵子树内的果实数量,同时清空。
所有操作可持久化,每次操作会告诉你前驱版本的编号…
数据范围
思路
先来考虑不持久化怎么做。
树链剖分,维护
1.操作就在链上跳,找到第一个满足要求的操作,子树清空,找不到就将到根的路径所有节点维护的那个最小值减去一个值。
2.子树查询
可持久化的话…加标记标记永久化一下。
清空的话…直接连到0号版本的树上(还有这种操作?.jpg),然后再将从父亲到根的路径都加上sum。
代码
#include<bits/stdc++.h> using namespace std; template<typename T> void read(T &x,char ch=getchar()) { for (x=0;ch<'0'||ch>'9';ch=getchar()); for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar()); } #define MAXN 100010 #define INF 1LL<<60 typedef long long ll; int T,n,m,ord,sta,opt,u,v,t; int seq[MAXN],size[MAXN],son[MAXN],fa[MAXN],top[MAXN],deep[MAXN],dfn[MAXN],rdfn[MAXN]; ll w[MAXN],FK; namespace PT { struct Node{ Node *ch[2]; ll mn,add,sum; void pushup() { mn=min(ch[0]->mn,ch[1]->mn)+add; sum=ch[0]->sum+ch[1]->sum; } }*null=new Node; Node pool[MAXN*400]; Node *tail; Node *ver[MAXN]; Node *NewNode(Node *f=0) { Node *p=tail++; if (f) { p->ch[0]=f->ch[0];p->ch[1]=f->ch[1]; p->mn=f->mn; p->add=f->add; p->sum=f->sum; } else p->ch[0]=p->ch[1]=null; return p; } Node *build(int l,int r) { Node *ret=NewNode(); if (l==r) { ret->mn=w[seq[l]]; ret->add=0; ret->sum=0; return ret; } int mid=(l+r)>>1; ret->ch[0]=build(l,mid); ret->ch[1]=build(mid+1,r); ret->pushup(); return ret; } void init() { tail=pool; null->ch[0]=null->ch[1]=null; null->mn=INF; null->sum=0; null->add=0; ver[0]=build(1,n); } void add(int pos,int l,int r,Node* &now,ll val) { now=NewNode(now); if (l==r) { now->sum+=val; return; } int mid=(l+r)>>1; if (pos<=mid) add(pos,l,mid,now->ch[0],val); else add(pos,mid+1,r,now->ch[1],val); now->pushup(); } void Iadd(int L,int R,int l,int r,Node* &now,ll val) { now=NewNode(now); if (L<=l && r<=R) { now->add+=val; now->mn+=val; return; } int mid=(l+r)>>1; if (L<=mid) Iadd(L,R,l,mid,now->ch[0],val); if (R>mid) Iadd(L,R,mid+1,r,now->ch[1],val); now->pushup(); } void clear(int L,int R,int l,int r,ll tag,Node* &now,Node *pre) { if (L<=l && r<=R) { FK+=now->sum; now=NewNode(pre); now->add-=tag; now->mn-=tag; return; } now=NewNode(now); int mid=(l+r)>>1; if (L<=mid) clear(L,R,l,mid,tag+now->add,now->ch[0],pre->ch[0]); if (R>mid) clear(L,R,mid+1,r,tag+now->add,now->ch[1],pre->ch[1]); now->pushup(); } int query_mn(int L,int R,int l,int r,Node *now,ll val) { if (now->mn >= val) return 0; if (l==r) return seq[l]; int mid=(l+r)>>1; if (R>mid) { int ret=query_mn(L,R,mid+1,r,now->ch[1],val-now->add); if (ret) return ret; } if (L<=mid) return query_mn(L,R,l,mid,now->ch[0],val-now->add); return 0; } void debug(int l,int r,Node *now) { printf("[%d,%d]:mn=%lld,add=%lld,sum=%lld\n",l,r,now->mn,now->add,now->sum); if (l==r) return; int mid=(l+r)>>1; debug(l,mid,now->ch[0]); debug(mid+1,r,now->ch[1]); } } struct edge{ int s,t,next; }e[MAXN<<1]; int head[MAXN],cnt; void addedge(int s,int t) { e[cnt].s=s;e[cnt].t=t;e[cnt].next=head[s];head[s]=cnt++; e[cnt].t=s;e[cnt].s=t;e[cnt].next=head[t];head[t]=cnt++; } void dfs(int node,int lastfa,int de) { fa[node]=lastfa; deep[node]=de; size[node]=1; son[node]=0; for (int i=head[node];i!=-1;i=e[i].next) if (e[i].t!=lastfa) { dfs(e[i].t,node,de+1); size[node]+=size[e[i].t]; if (size[e[i].t]>size[son[node]]) son[node]=e[i].t; } } void dfs2(int node,int lastfa,int tp) { top[node]=tp; dfn[node]=++ord; seq[ord]=node; if (son[node]) dfs2(son[node],node,tp); for (int i=head[node];i!=-1;i=e[i].next) if (e[i].t!=lastfa && e[i].t!=son[node]) dfs2(e[i].t,node,e[i].t); rdfn[node]=ord; } int get_mn(int sta,int u,ll v) { while (u) { int ret=PT::query_mn(dfn[top[u]],dfn[u],1,n,PT::ver[sta],v); if (ret) return ret; u=fa[top[u]]; } return 0; } void mo_add(int sta,int u,ll v) { while (u) { PT::Iadd(dfn[top[u]],dfn[u],1,n,PT::ver[sta],v); u=fa[top[u]]; } return; } int main() { read(T); while (T--) { read(n),read(m);n++; memset(head,0xff,sizeof(head)); cnt=0; for (int i=2;i<=n;i++) { read(u);u++; addedge(i,u); read(w[i]); } w[1]=INF; dfs(1,0,1); ord=0; dfs2(1,1,1); PT::init(); for (int i=1;i<=m;i++) { read(sta),read(opt),read(u);u++; if (opt==1) { read(v); t=get_mn(sta,u,v); printf("%d\n",max(0,t-1)); if (t) { PT::ver[i]=PT::ver[sta]; FK=0; PT::clear(dfn[t],rdfn[t],1,n,0,PT::ver[i],PT::ver[0]); mo_add(i,fa[t],FK); } else { PT::ver[i]=PT::ver[sta]; PT::add(dfn[u],1,n,PT::ver[i],v); mo_add(i,u,-v); } } else { PT::ver[i]=PT::ver[sta]; FK=0; PT::clear(dfn[u],rdfn[u],1,n,0,PT::ver[i],PT::ver[0]); printf("%lld\n",FK); mo_add(i,fa[u],FK); } } } return 0; }
Saboteur (Challenge)
题意简述
给你一个图,让你删除某些点,使得剩下的点形成一棵树。
最小化删除权值和。
数据范围
子任务:
1.
2.
3.
4.
5.完全图
6.轮子图
7.随机图
思路
这题甩锅给同学了,代码就不发了……
子任务1暴力,子任务3基环树DP一下,子任务4缩一缩点,子任务5保留两个权值最大的,子任务6两种情况,中间点删了就贪心,不删就DP一下。
子任务7
随机一个加点顺序,如果不成环就加,最后选权值最大的树。
多次随机,贪心优化。
子任务2用随机跑了。
被日本min_25踩了…代码1千行…
OI选手和人家完全没法比啊……
- [题解]CodeChef JUNE Challenge 17
- [题解]CodeChef APRIL Challenge 17
- CodeChef November Challenge 2013 题解
- CodeChef March Challenge 2017 题解
- Codechef June Challenge 2017 #Persistent oak -- 树链剖分+主席树
- [主席树+哈希] Codechef June Challenge 2017 #CLONEME
- Codechef July Challenge 2014部分题解
- Codechef 2017 March Challenge 简要题解
- Codechef June Challenge 2014 #Sereja and Arcs -- 容斥 + 阈值 + 树状数组
- [CodeChef September Challenge 2012]Knight Moving(KNGHTMOV)题解翻译
- codechef December Challenge 2012
- codechef December Challenge 2012
- codechef December Challenge 2012
- codechef May challenge A
- codechef May challenge B
- codechef May challenge C
- CodeChef May Challenge 2014
- codechef July Challenge 2014
- iOS之Runtime原理解读
- ABAQUS显示如下错误 ***ERROR: An error occurred during a write access to
- Cardboard游戏(iOS)耳机线控实践
- C语言中strcpy,strcmp,strlen,strcat函数原型
- 分享一个酷炫的粒子动画实现
- [题解]CodeChef JUNE Challenge 17
- android binder机制,注册系统服务---服务端servicemanager
- android中点击事件的复用
- uva1636概率
- 强分类器-----提升树的原理和推导
- 主题三 编译过程介绍---- 15.编译过程简介
- Linux如何配置ftp服务器、给ftp服务器添加访问用户
- C++学习:你该了解一点C++的设计模式之单例模式
- springboot使用定时任务、异步