Code Chef January Challenge 2019题解

传送门

\(div2\)那几道题不来做了太水了……

\(DPAIRS\)

一个显然合法的方案:\(A\)最小的和\(B\)所有连,\(A\)剩下的和\(B\)最大的连

算了咕上瘾了,咕咕咕

const int N=2e5+5;
int A[N],B[N],id[N],mxb,mxa,n,m;
int main(){
// freopen("testdata.in","r",stdin);
n=read(),m=read(),A[0]=inf,B[0]=-inf;
fp(i,1,n){
A[i]=read();
if(A[i]<A[mxa])mxa=i;
}
fp(i,1,m){
B[i]=read();
if(B[i]>B[mxb])mxb=i;
}
fp(i,1,m)print(mxa-1),print(i-1),sr[C]='\n';
fp(i,1,n)if(i!=mxa)print(i-1),print(mxb-1),sr[C]='\n';
return Ot(),0;
}

\(DIFNEIGH\)

还能咋样分类讨论吧……

//minamoto
#include<bits/stdc++.h>
#define R register
#define inf 0x3f3f3f3f
#define inline __inline__ __attribute__((always_inline))
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
using namespace std;
int n,m;
int main(){
// freopen("testdata.in","r",stdin);
int T;scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
if(n==1){
switch(m){
case 1:printf("%d\n%d\n",1,1);break;
case 2:printf("%d\n%d %d\n",1,1,1);break;
default:{
printf("%d\n",2);
fp(i,1,m)printf("%d%c",(i&3)<=1?1:2," \n"[i==m]);
break;
}
}
}else if(n==2){
switch(m){
case 1:printf("%d\n%d\n%d\n",1,1,1);break;
case 2:printf("%d\n%d %d\n%d %d\n",2,1,1,2,2);break;
default:{
printf("%d\n",3);
fp(i,1,m)printf("%d%c",i%3+1," \n"[i==m]);
fp(i,1,m)printf("%d%c",i%3+1," \n"[i==m]);
break;
}
}
}else if(m==1){
switch(n){
case 1:printf("%d\n%d\n",1,1);break;
case 2:printf("%d\n%d\n%d\n",1,1,1);break;
default:{
printf("%d\n",2);
fp(i,1,n)printf("%d%c",(i&3)<=1?1:2," \n"[i==n]);
break;
}
}
}else if(m==2){
switch(n){
case 1:printf("%d\n%d %d\n",1,1,1);break;
case 2:printf("%d\n%d %d\n%d %d\n",2,1,1,2,2);break;
default:{
printf("%d\n",3);
fp(i,1,n)printf("%d %d\n",i%3+1,i%3+1);
break;
}
}
}else{
printf("%d\n",4);
fp(i,1,n){
switch(i&3){
case 0:fp(j,1,m)printf("%d%c",(j&3)<=1?1:2," \n"[j==m]);break;
case 2:fp(j,1,m)printf("%d%c",(j&3)<=1?2:1," \n"[j==m]);break;
case 1:fp(j,1,m)printf("%d%c",(j&3)<=1?3:4," \n"[j==m]);break;
case 3:fp(j,1,m)printf("%d%c",(j&3)<=1?4:3," \n"[j==m]);break;
}
}
}
}
return 0;
}

\(EARTSEQ\)

我们去选它们两两之间的\(\gcd\),那么等价于选\(n\)个元素,两两之间互质,且\(a_i\)和\(a_{i+2}\)也要互质

那么我们让区间\(\gcd\)以\(2,3,5,2,3,5...\)循环下去就好了,有可能\(n\)不一定是\(3\)的倍数,所以后面可以加几个特殊的\(\gcd\)进去

还要满足相邻两个数的\(\gcd\)只有\(2,3,5,...\)之类的,也就是说另外一个因子也要互质,可以令另外一个因子为一个质数,那么直接取前\(50000\)个质数可以保证这一部分绝对互质

//minamoto
#include<bits/stdc++.h>
#define R register
#define inf 0x3f3f3f3f
#define inline __inline__ __attribute__((always_inline))
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
const int N=1e6+5;
bitset<N>vis;int p[N],m;
void init(int n=N-5){
fp(i,2,n){
if(!vis[i])p[++m]=i;
for(R int j=1;j<=m&&1ll*i*p[j]<=n;++j){
vis[i*p[j]]=1;
if(i%p[j]==0)break;
}
}
}
int main(){
// freopen("testdata.in","r",stdin);
init();
int T,n;scanf("%d",&T);
while(T--){
scanf("%d",&n);
switch(n%3){
case 0:{
for(R int i=1;i<=n;i+=3)printf("%d %d %d ",6*p[i+10],15*p[i+11],10*p[i+12]);
puts("");
break;
}
case 1:{
for(R int i=1;i<=n-4;i+=3)printf("%d %d %d ",6*p[i+10],15*p[i+11],10*p[i+12]);
printf("%d %d %d %d\n",2*7*p[n+10-3],7*11*p[n+10-2],11*13*p[n+10-1],13*2*p[n+10]);
break;
}
case 2:{
for(R int i=1;i<=n-5;i+=3)printf("%d %d %d ",6*p[i+10],15*p[i+11],10*p[i+12]);
printf("%d %d %d %d %d\n",2*7*p[n+10-4],7*11*p[n+10-3],
11*13*p[n+10-2],13*17*p[n+10-1],17*2*p[n+10]);
break;
}
}
}
return 0;
}

\(XYPIZQ\)

这好像是初中数学题……

话说中文版题面为啥不把\(x,y,z\)的限制条件写完整啊……

其实\(3\)和\(1\)差不多,\(2\)和\(4\)差不多,剩下的画画图就出来了

//minamoto
#include<bits/stdc++.h>
#define R register
#define inf 0x3f3f3f3f
#define inline __inline__ __attribute__((always_inline))
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
R int res,f=1;R char ch;
while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
return res*f;
}
int n,t,x,y,z,tmp;
void print(int a){
int g=__gcd(a,tmp);
printf("%d %d\n",a/g,tmp/g);
}
int main(){
// freopen("testdata.in","r",stdin);
for(int T=read();T;--T){
n=read(),t=read(),x=read(),y=read(),z=read(),tmp=2*n+1;
if(t==3)swap(x,z),t=1;else if(t==4)t=2;
if(t==1){
if(!y)print(1);
else if(x==z)print(x);
else print(tmp-z);
}else print(tmp-2*y);
}
return 0;
}

\(GRAPART\)

\(k=1\)的情况,就是奇数和偶数层数的节点个数相同

\(k\)最大等于\(2\)就够了,因为这样已经可以奇偶分层了。然后把所有叶子的颜色改一下就可以了

//minamoto
#include<bits/stdc++.h>
#define R register
#define inf 0x3f3f3f3f
#define inline __inline__ __attribute__((always_inline))
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
R int res,f=1;R char ch;
while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
return res*f;
}
char sr[1<<21],z[20];int K=-1,Z=0;
inline void Ot(){fwrite(sr,1,K+1,stdout),K=-1;}
void print(R int x){
if(K>1<<20)Ot();if(x<0)sr[++K]='-',x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++K]=z[Z],--Z);sr[++K]=' ';
}
const int N=10005;
struct eg{int v,nx;}e[N<<1];int head[N],tot;
inline void add(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
bool ans[N],lf[N];int n,res;
void dfs(int u,int fa){
lf[u]=1,ans[u]?++res:--res;
go(u)if(v!=fa)ans[v]=ans[u]^1,dfs(v,u),lf[u]=0;
}
int main(){
// freopen("testdata.in","r",stdin);
for(int T=read();T;--T){
n=read(),tot=0,res=0;
memset(head,0,(n+1)<<2);
for(R int i=1,u,v;i<n;++i)u=read(),v=read(),add(u,v),add(v,u);
dfs(1,0);
print(res?2:1),sr[K]='\n';
fp(i,1,n)if(lf[i]){
if(!ans[i]&&res<0)ans[i]=1,res+=2;
else if(ans[i]&&res>0)ans[i]=0,res-=2;
}
fp(i,1,n)if(ans[i])print(i);sr[K]='\n';
fp(i,1,n)if(!ans[i])print(i);sr[K]='\n';
}
return Ot(),0;
}

\(PARRTY\)

首先这题有两种暴力

一个是每次询问\(O(n+m)\)的,即枚举区间中的每一个位置,每次把所有和它有边相连的点打上标记,一旦查询到一个有标记的点说明就\(gg\)了

一个是每次询问\(O(k^2\log n)\)的,即我们建主席树,然后枚举询问,看看前面的其它询问区间里是否有元素

所以我们只要把这两种暴力结合起来就可以\(A\)了。法老说这叫设阈值,我觉得就是骗分啊……

我们设一个阈值\(S\),当\(k>S\)时使用第一种方法,当\(k<S\)时使用第二种方法,这样的话时间复杂度就是\(O({n^2\over S}+nS\log n)\),亲测取\(S=100\)的时候跑得飞快

据说还有大佬用莫队写的然而我不会就是了

//minamoto
#include<bits/stdc++.h>
#define R register
#define fi first
#define se second
#define inline __inline__ __attribute__((always_inline))
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=E[i].v;i;i=E[i].nx,v=E[i].v)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
R int res,f=1;R char ch;
while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
return res*f;
}
const int N=2e5+5,M=(N<<7)+5;
inline void swap(R int &x,R int &y){R int t=x;x=y,y=t;}
struct node;typedef node* ptr;
struct node{
ptr lc,rc;int sz;
inline node();
}e[M],*rt[N];int cnt;
inline node::node(){lc=rc=e;}
void update(ptr &p,int l,int r,int x){
(e+(++cnt))->lc=p->lc,(e+cnt)->rc=p->rc,(e+cnt)->sz=p->sz+1,p=e+cnt;
if(l==r)return;int mid=(l+r)>>1;
x<=mid?update(p->lc,l,mid,x):update(p->rc,mid+1,r,x);
}
bool query(ptr p,ptr q,int l,int r,int ql,int qr){
if(p->sz-q->sz==0||ql<=l&&qr>=r)return p->sz-q->sz>0;
int mid=(l+r)>>1;
if(ql<=mid&&query(p->lc,q->lc,l,mid,ql,qr))return true;
if(qr>mid&&query(p->rc,q->rc,mid+1,r,ql,qr))return true;
return false;
}
struct eg{int v,nx;}E[N];int head[N],tot;
inline void add(R int u,R int v){E[++tot]={v,head[u]},head[u]=tot;}
bool vis[N];int n,m,q,S,k;pair<int,int>p[N];
int main(){
// freopen("testdata.in","r",stdin);
for(int T=read();T;--T){
n=read(),m=read(),S=100;
for(R int i=1,u,v;i<=m;++i){
u=read(),v=read();if(u<v)swap(u,v);
add(u,v);
}
rt[0]=e;
fp(u,1,n){
rt[u]=rt[u-1];
go(u)update(rt[u],1,n,v);
}
q=read();
while(q--){
k=read();bool flag=1;
fp(i,1,k)p[i].fi=read(),p[i].se=read();
sort(p+1,p+1+k);
if(k>S){
memset(vis,0,n+1);
for(R int i=k;i&&flag;--i)
for(R int j=p[i].se;j>=p[i].fi;--j){
if(vis[j]){flag=0;break;}
go(j)vis[v]=1;
}
}else{
for(R int i=1;i<=k&&flag;++i)
for(R int j=1;j<=i;++j){
if(query(rt[p[i].se],rt[p[i].fi-1],1,n,p[j].fi,p[j].se))
{flag=0;break;}
}
}
puts(flag?"YES":"NO");
}
memset(head,0,(n+1)<<2),tot=cnt=0;
}
return 0;
}

\(MXDIST\)

我很想知道为什么原题题面\(n\leq 200000\)而中文版题面里\(n\leq 50000\)……\(RE\)了一个上午去看了看原题题面才发现挂在哪里……

易知最远欧几里得距离肯定在凸包上,而且这个东西是用旋转卡壳做的。所以我们可以分块,设块的大小为\(S\),再对每块内部做一次凸包。关于两个凸包的合并,如果我们分别记录上凸壳和下凸壳,那么就可以做到合并\(O(n)\),其中\(n\)是两个凸包的大小总和。然后我们再开一个\(ST\)表,对于每个询问,先把零散的部分的凸包暴力求出来,然后再和整块的凸包合并,在上面跑旋转卡壳就可以知道答案了

然后我有几个问题不太明白……首先是为啥要分块之后再开\(ST\)表而不能直接开\(ST\)表,后来想了想是时间要炸,因为它\(ST\)表合并的时候一层的复杂度是\(2^i(n-2^i)\),如果分块之后可以把\(n\)降到\({n\over S}\)级别,也就是说通过增大后面询问的复杂度来把前期预处理的复杂度降下来

还有就是……这旋转卡壳的复杂度是\(O(凸包大小)\)的吧……那这玩意儿的复杂度是\(O(nq)\)的吧……我是不是只能理解为因为全是整数点很难构造出凸包上点数很多的数据啊……

//minamoto
#include<bits/stdc++.h>
#define R register
#define fi first
#define se second
#define ll long long
#define pb push_back
#define IT vector<pair<node,int> >::iterator
#define inline __inline__ __attribute__((always_inline))
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
R int res,f=1;R char ch;
while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
return res*f;
}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
void print(R ll x){
if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=200005,S=15,L=15005;
struct node{
int x,y;
inline node(){}
inline node(R int xx,R int yy):x(xx),y(yy){}
inline node operator +(const node &b)const{return node(x+b.x,y+b.y);}
inline node operator -(const node &b)const{return node(x-b.x,y-b.y);}
inline ll operator *(const node &b)const{return 1ll*x*b.y-1ll*y*b.x;}
inline bool operator <(const node &b)const{return x<b.x||x==b.x&&y<b.y;}
inline ll norm(){return 1ll*x*x+1ll*y*y;}
}p[N];
struct Convex{
vector<node>up,dw;
inline Convex(){}
inline Convex(const vector<node> &b){up=b,dw=b,build();}
Convex operator +(const Convex &b)const{
Convex c;
c.up.resize(up.size()+b.up.size());
merge(up.begin(),up.end(),b.up.begin(),b.up.end(),c.up.begin());
c.dw.resize(dw.size()+b.dw.size());
merge(dw.begin(),dw.end(),b.dw.begin(),b.dw.end(),c.dw.begin());
c.build();
return c;
}
void build(){
int n=up.size(),m=0;
fp(i,0,n-1){
while(m>1&&(up[i]-up[m-2])*(up[m-1]-up[m-2])<=0)--m;
up[m++]=up[i];
}
up.resize(m);
n=dw.size(),m=0;
fp(i,0,n-1){
while(m>1&&(dw[i]-dw[m-2])*(dw[m-1]-dw[m-2])>=0)--m;
dw[m++]=dw[i];
}
dw.resize(m);
}
ll solve(){
vector<node>st=dw;
fd(i,up.size()-2,0)st.pb(up[i]);
int n=st.size()-1;ll res=0;
for(R int i=0,j=1;i<n;++i){
while((st[j+1]-st[i]).norm()>(st[j]-st[i]).norm())j=(j+1)%n;
cmax(res,(st[j]-st[i]).norm()),cmax(res,(st[j+1]-st[i+1]).norm());
}
return res;
}
}st[L][17];
int n,m,Log[L],rt[N];vector<pair<node,int> >c[L];
Convex rmq(int l,int r){
if(l>r)return Convex();
int k=Log[r-l+1];
return st[l][k]+st[r-(1<<k)+1][k];
}
int main(){
// freopen("testdata.in","r",stdin);
// freopen("testdata.out","w",stdout);
n=read(),m=(n-1)/S+1;
fp(i,1,n)p[i].x=read(),p[i].y=read(),rt[i]=(i-1)/S+1;
fp(i,1,m){
int l=(i-1)*S+1,r=min(n,i*S);
fp(j,l,r)c[i].pb(make_pair(p[j],j));
sort(c[i].begin(),c[i].end());
vector<node>point;
for(IT it=c[i].begin();it!=c[i].end();++it)point.pb(it->fi);
st[i][0]=Convex(point);
}
fp(i,2,m)Log[i]=Log[i>>1]+1;
fp(j,1,Log[m])fp(i,1,m-(1<<j)+1)st[i][j]=st[i][j-1]+st[i+(1<<(j-1))][j-1];
int q=read(),l,r;
while(q--){
l=read(),r=read();
if(rt[l]==rt[r]){
vector<node>point;
for(IT it=c[rt[l]].begin();it!=c[rt[l]].end();++it)
if(it->se>=l&&it->se<=r)point.pb(it->fi);
Convex res(point);
print(res.solve());
}else{
vector<node>pointl,pointr;
for(IT it=c[rt[l]].begin();it!=c[rt[l]].end();++it)
if(it->se>=l&&it->se<=r)pointl.pb(it->fi);
for(IT it=c[rt[r]].begin();it!=c[rt[r]].end();++it)
if(it->se>=l&&it->se<=r)pointr.pb(it->fi);
Convex res=rmq(rt[l]+1,rt[r]-1)+Convex(pointl)+Convex(pointr);
print(res.solve());
}
}
return Ot(),0;
}
上一篇:普通用户修改.bash_profile 权限问题


下一篇:2个list取差集