传送门node
咕咕c++
const int N=1005; int a[N],n,T; int main(){ for(scanf("%d",&T);T;--T){ scanf("%d",&n); fp(i,1,10)a[i]=n%10,n/=10; R int fl=1; fp(i,1,9)if(a[i]<a[i+1]){fl=0;break;} if(!fl)puts("Impossible"); else printf("%d\n",a[1]); } return 0; }
枚举心里,那么三个点合法当且仅当到这个心里距离相同,组合数算一下就好了数组
typedef long long ll; const int N=2005; int x[N],y[N],n;ll res,dis[N]; inline ll d(R int i,R int j){return 1ll*(x[i]-x[j])*(x[i]-x[j])+1ll*(y[i]-y[j])*(y[i]-y[j]);} inline ll calc(R int x){return 1ll*x*(x-1)*(x-2)/6;} int main(){ scanf("%d",&n); fp(i,1,n)scanf("%d%d",&x[i],&y[i]); fp(i,1,n){ R int tot=0; fp(j,1,n)if(i!=j)dis[++tot]=d(i,j); sort(dis+1,dis+1+tot); for(R int l=1,r=1;l<=tot;l=r){ while(r<=tot&&dis[r]==dis[l])++r; res+=calc(r-l); } } printf("%lld\n",res); return 0; }
首先确定存在一个分界点,知足前面是\(A\)掉的,后面是没交过或者fst的,记最后一个\(A\)掉的人为\(i\),那么\(i\)以及以前要知足\(a_i\)递增,\(i\)以后的要能分红两个集合,一个是fst的,一个是没交的,两个都要知足\(a_i\)递增,且fst的全部人的编号都小于没交的人的编号,同时任意一个\(a_j<a_i\)的\(j\)都必须是fst的,直接暴力\(check\)就好了ui
//quming #include<bits/stdc++.h> #define R register #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;} template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;} using namespace std; const int N=505; int a[N],stx[N],sty[N],id[N],fl[N],fr[N],tx,ty,n,T,l,r; bool ck(int l,int r,int tt){ if(l>=r)return 1; int top=0; fp(i,l,r)id[++top]=i; sort(id+1,id+1+top,[](const int &x,const int &y){return a[x]<a[y];}); fl[0]=fr[top+1]=1,id[0]=l-1,id[top+1]=r+1; fp(i,1,top)fl[i]=fl[i-1]&(id[i]>id[i-1]); fd(i,top,1)fr[i]=fr[i+1]&(id[i]<id[i+1]); fp(i,tt,top)if(fl[i]&&fr[i+1])return true; return false; } int main(){ // freopen("testdata.in","r",stdin); for(scanf("%d",&T);T;--T){ scanf("%d",&n),l=n+1,r=0; fp(i,1,n)scanf("%d",&a[i]); a[n+1]=n+1,a[0]=0; fp(i,0,n){ if(i&&a[i]<a[i-1])break; if(ck(i+1,n,a[i]-i))cmin(l,i),cmax(r,i); } if(l>r)l=r=-1; printf("%d %d\n",l,r); } return 0; }
这个数字\(s\)要能被表示成若干个\({10^k-1\over 9}\)之和,那么就是\(9s\)要能表示成若干个\(10^k-1\)之和,咱们枚举数字个数\(p\),那么就是\(9s+p\)能被表示成\(10^k\)之和,条件就是\(p\)大于等于全部数位之和,且因为一次进位是让某一位-10,另外一位+1,因此还要知足\(p\)和全部数位之和在模\(9\)意义下相等。显然\(p\)是\(O(|s|)\)级别的,根据\(01\)计算器的原理,复杂度\(O(|s|)\)this
//quming #include<bits/stdc++.h> #define R register #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;} template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;} using namespace std; const int N=2e6+5; char s[N];int a[N],q[N],h,t,n,res,T,sum; inline int min(R int x,R int y){return x<y?x:y;} int calc(){ fp(k,1,23333333){ R int i=1; while(a[i]==9)a[i++]=0,sum-=9; ++a[i],++sum; if(k>=sum&&sum%9==k%9)return k; } } int main(){ // freopen("testdata.in","r",stdin); for(scanf("%d",&T);T;--T){ scanf("%s",s+1),n=strlen(s+1); fp(i,1,n)a[i]=s[n-i+1]-'0',a[i]=a[i]*9; fp(i,1,n-1)a[i+1]+=a[i]/10,a[i]%=10; for(;a[n]>9;++n)a[n+1]=a[n]/10,a[n]%=10; fp(i,n+1,n+233333)a[i]=0; sum=0; fp(i,1,n)sum+=a[i]; printf("%d\n",calc()); } return 0; }
对于某一个元素,咱们把对他进行的全部操做放在时间轴上,一个push记为+1,一个pop记为-1,那么一次时间t时的query,就是找到一个最大的i,知足[i,t]之和大于等于pos,那么这个i处确定是一个push,且这个push的元素即为答案了spa
那么对于区间push和区间pop直接离线,而后就能维护每一个元素的全部操做的时间轴了code
代码里实现的时候略微有点不一样,由于查询[i,t]太难写了,因此我代码里是把时间轴反过来,而后查询一个最小的知足条件的前缀和的位置的,且push记为-1,pop记为+1,因此看代码的时候注意一下get
//quming #include<bits/stdc++.h> #define R register #define pb push_back #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;} template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;} using namespace std; const int N=2e5+5; inline int min(R int x,R int y){return x<y?x:y;} struct node;typedef node* ptr; struct node{ ptr lc,rc;int t,mn; inline void ppd(R int x){t+=x,mn+=x;} inline void pd(){if(t)lc->ppd(t),rc->ppd(t),t=0;} inline void upd(){mn=min(lc->mn,rc->mn);} }e[N<<2],*rt,*pp=e; int a[N],n,q; char s[15];vector<int>ad[N],ed[N],qr[N]; void build(ptr &p,int l,int r){ p=++pp;if(l==r)return; int mid=(l+r)>>1; build(p->lc,l,mid),build(p->rc,mid+1,r); p->upd(); } int K,ans,ANS[N]; void query(ptr p,int l,int r,int x){ if(l==r)return ans=r,void(); int mid=(l+r)>>1;p->pd(); if(!ans&&x<=mid&&p->lc->mn<=K)query(p->lc,l,mid,x); if(!ans&&x<=r&&p->rc->mn<=K)query(p->rc,mid+1,r,x); } int get(ptr p,int l,int r,int x){ if(l==r)return p->mn; int mid=(l+r)>>1;p->pd(); return x<=mid?get(p->lc,l,mid,x):get(p->rc,mid+1,r,x); } void update(ptr p,int l,int r,int ql,int qr,int v){ if(ql<=l&&qr>=r)return p->ppd(v),void(); int mid=(l+r)>>1;p->pd(); if(ql<=mid)update(p->lc,l,mid,ql,qr,v); if(qr>mid)update(p->rc,mid+1,r,ql,qr,v); p->upd(); } int main(){ // freopen("testdata.in","r",stdin); scanf("%d%d",&n,&q); build(rt,1,q); for(R int i=1,l,r,v,id;i<=q;++i){ scanf("%s",s+1); switch(s[2]){ case 'u':{ scanf("%d%d%d",&l,&r,&v); a[q-i+1]=v,ad[l].pb(q-i+1),ed[r+1].pb(q-i+1); break; } case 'o':{ scanf("%d%d",&l,&r); ed[l].pb(q-i+1),ad[r+1].pb(q-i+1); break; } case 'i':{ scanf("%d%d",&id,&v); a[q-i+1]=v,qr[id].pb(q-i+1); break; } } } fp(i,1,n){ for(auto v:ad[i])update(rt,1,q,v,q,-1); for(auto v:ed[i])update(rt,1,q,v,q,1); for(auto v:qr[i]){ K=get(rt,1,q,v)-a[v],ans=0; query(rt,1,q,v); // printf("%d %d\n",v,ans); ANS[v]=a[ans]; } } fd(i,q,1)if(ANS[i])printf("%d\n",ANS[i]); return 0; }
对于\(C\),咱们从后往前来枚举\(i\)并判断\([i+1,n]\)是否可行,因为是从后往前,那么至关于每次往集合里加入一个数,咱们记\(ql\)和\(qr\)表示sort以后,开头最长值域和下标都递增的长度以及结尾最长值域和下标都递增的长度,每次用新插入的这个数更新ql和qr就好了,用平衡树维护一下便可,代码写的FHQtreapit
//quming #include<bits/stdc++.h> #define R register #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;} template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;} using namespace std; unsigned int aaa=19260817; inline unsigned int rd(){aaa^=aaa>>15,aaa+=aaa<<12,aaa^=aaa>>3;return aaa;} const int N=2e5+5; struct node;typedef node* ptr; struct node{ ptr lc,rc;int v,sz;unsigned int pr; inline void init(R int val){v=val,pr=rd(),sz=1;} inline ptr upd(){return sz=lc->sz+rc->sz+1,this;} }e[N],*rt=e;int tot; inline ptr newnode(R int v){return e[++tot].init(v),(e+tot)->lc=(e+tot)->rc=e,e+tot;} void split(ptr p,int k,ptr &s,ptr &t){ if(p==e)return s=t=e,void(); if(p->v<=k)s=p,split(p->rc,k,p->rc,t); else t=p,split(p->lc,k,s,p->lc); p->upd(); } ptr merge(ptr s,ptr t){ if(s==e)return t;if(t==e)return s; if(s->pr<t->pr)return s->rc=merge(s->rc,t),s->upd(); return t->lc=merge(s,t->lc),t->upd(); } void insert(int k){ ptr s,t; split(rt,k,s,t); rt=merge(merge(s,newnode(k)),t); } void erase(int k){ ptr s,t,p; split(rt,k,s,t),split(s,k-1,s,p),p=merge(p->lc,p->rc); rt=merge(merge(s,p),t); } int rk(int k){ ptr s,t;int now; split(rt,k-1,s,t);now=s->sz+1; return rt=merge(s,t),now; } int Kth(ptr p,int k){ if(p->lc->sz==k-1)return p->v; if(p->lc->sz>=k)return Kth(p->lc,k); return Kth(p->rc,k-p->lc->sz-1); } int Pre(int k){ ptr s,t;int now; split(rt,k-1,s,t),now=Kth(s,s->sz); return rt=merge(s,t),now; } int nxt(int k){ ptr s,t;int now; split(rt,k,s,t),now=Kth(t,1); return rt=merge(s,t),now; } int ok[N],a[N],kr[N],n,ql,qr,T,l,r; int main(){ // freopen("testdata.in","r",stdin); for(scanf("%d",&T);T;--T){ rt=e,tot=0; scanf("%d",&n),l=n+1,r=0; fp(i,1,n)scanf("%d",&a[i]),kr[a[i]]=i,ok[i]=0; a[0]=0,a[n+1]=n+1,kr[0]=0,kr[n+1]=n+1,ok[0]=ok[n+1]=0; ok[n+1]=1; insert(0),insert(n+1),ql=qr=2; R int cnt=2; fd(i,n,1){ R int pl=Pre(a[i]),pr=nxt(a[i]); R int sz=rk(pl); if(ql>=sz){ if(i>kr[pl]&&i<kr[pr])++ql; else if(i<kr[pl])ql=sz; else ql=sz+1; } sz=cnt-(rk(pr)-1); if(qr>=sz){ if(i>kr[pl]&&i<kr[pr])++qr; else if(i>kr[pr])qr=sz; else qr=sz+1; } ++cnt; insert(a[i]); ok[i]=(ql+qr>=cnt&&ql>=a[i-1]-(i-1)+1); } fp(i,0,n){ if(i&&a[i]<a[i-1])break; if(ok[i+1])cmin(l,i),cmax(r,i); } if(l>r)l=r=-1; printf("%d %d\n",l,r); } return 0; }
首先相似于CF840B,若是咱们已经肯定了每一个点的度数的奇偶,那么必定能够构造出一组合法方案class
因为这个构造只须要一棵生成树就能够完成,那么咱们把标号大边的尽可能留在生成树上,这样标号小的边就能够所有选了
先来考虑某一棵生成树,把能够选的所有选完以后,就是树上某些点为奇某些为偶,咱们能够只考虑偶数点,对于任意两个点,咱们能够对他们路径上的全部边取反,从而只改变这两个点的状态而不改变路径上其它点的状态,因此可知最终的偶数点只有\(0/1\)两种状况
那么再来考虑边,咱们建一个并查集重构树,保证序号小的边深度浅,那么从上到下一次考虑每条边,选了一条边以后就至关于对于它所链接的两个连通块中各改变一个点的状态,咱们发现若是两个连通块都是偶数点为\(0\)的状况,这条边选了以后最终答案必定变劣,这种状况下不选,其余状况下均可以选,用树状数组维护一下便可
//quming #include<bits/stdc++.h> #define R register #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;} template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;} using namespace std; const int N=2e6+5; 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;} int dfn[N],d[N],low[N],c[N],fa[N],fr[N],to[N],vis[N],bl[N],ls[N],rs[N]; int n,m,nd,cnt; inline void chg(R int x){for(;x<=n;x+=x&-x)c[x]^=1;} inline int qwq(R int x){R int res=0;for(;x;x-=x&-x)res^=c[x];return res;} inline int query(R int l,R int r){return qwq(r)^qwq(l-1);} inline int find(R int x){return fa[x]==x?x:fa[x]=find(fa[x]);} void dfs(int u){ if(u<=n)return dfn[u]=low[u]=++cnt,void(); dfn[u]=nd+1,low[u]=0; go(u)dfs(v),cmin(dfn[u],dfn[v]),cmax(low[u],low[v]); } int main(){ freopen("testdata.in","r",stdin); scanf("%d%d",&n,&m),nd=n; fp(i,1,m)scanf("%d%d",&fr[i],&to[i]),++fr[i],++to[i]; fp(i,1,n)fa[i]=i; for(R int i=m,u,v;i;--i){ u=find(fr[i]),v=find(to[i]); if(u==v)vis[i]=1,d[fr[i]]^=1,d[to[i]]^=1; else{ ++nd,fa[u]=fa[v]=fa[nd]=nd,ls[nd]=u,rs[nd]=v,bl[i]=nd; add(nd,u),add(nd,v); } } dfs(nd); fp(i,1,n)if(!d[i])chg(dfn[i]); fp(i,1,m)if(bl[i]){ R int l=query(dfn[ls[bl[i]]],low[ls[bl[i]]]); R int r=query(dfn[rs[bl[i]]],low[rs[bl[i]]]); if(l||r)vis[i]=1,chg(dfn[fr[i]]),chg(dfn[to[i]]); } fp(i,1,m)putchar(vis[i]+'0'); putchar('\n'); return 0; }