(SUMAGCD)
先去重,易知答案一定是一个数单独一组剩下的一组,前缀后缀(gcd)一下就行了
//quming
#include<bits/stdc++.h>
#define R register
#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;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=1e5+5;
int a[N],suf[N],Pre[N],n,T,mx;
int main(){
for(scanf("%d",&T);T;--T){
scanf("%d",&n),mx=0;
fp(i,1,n)scanf("%d",&a[i]);
sort(a+1,a+1+n),n=unique(a+1,a+1+n)-a-1;
if(n==1){printf("%d
",a[1]<<1);continue;}
Pre[0]=0;fp(i,1,n)Pre[i]=__gcd(a[i],Pre[i-1]);
suf[n+1]=0;fd(i,n,1)suf[i]=__gcd(suf[i+1],a[i]);
fp(i,1,n)cmax(mx,a[i]+__gcd(Pre[i-1],suf[i+1]));
printf("%d
",mx);
}
return 0;
}
(CHFING)
(1)到(k-1)肯定(gg),剩下的放到模(k)意义下,共有(k)个点,然后(n-1)条边,第(i)条边可以从(c)到((c+k+i)\%k),设(dis_c)表示到(c)点的最短路,那么(dis_c+p imes k)都是能被标识的,剩下的不行。然后再仔细讨论一下就行了
//quming
#include<bits/stdc++.h>
#define R register
#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;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
typedef long long ll;
int T,res,p;ll n,k;
const int P=1e9+7;
inline int calc(R int x){return (1ll*x*(x+1)>>1)%P;}
inline void upd(R int &x,R int y){(x+=y)>=P?x-=P:0;}
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
R int res=1;
for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
return res;
}
int main(){
for(scanf("%d",&T);T;--T){
scanf("%lld%lld",&n,&k),p=(k-1)/(n-1)%P,n%=P,k%=P;
res=add(mul(calc(p),n-1),mul(p+1,dec(k-1,mul(p,n-1))));
res=add(res,P);
printf("%d
",res);
}
return 0;
}
(LENTMO)
分情况讨论,如果(k=n)只有操作或不操作,如果(k)为奇数等价于(k=1),为偶数等价于(k=2)
//quming
#include<bits/stdc++.h>
#define R register
#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;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
typedef long long ll;
const int N=1e5+5;
int a[N],k,n,x,T;ll res,mx,sum[N];
int main(){
for(scanf("%d",&T);T;--T){
scanf("%d",&n),mx=res=0;
fp(i,1,n)scanf("%d",&a[i]);
scanf("%d%d",&k,&x);
fp(i,1,n)res+=a[i],a[i]=(a[i]^x)-a[i];
sort(a+1,a+1+n);sum[n+1]=0;
fd(i,n,1)sum[i]=sum[i+1]+a[i];
if(k==n)cmax(mx,sum[1]);
else if(k&1)fp(i,1,n)cmax(mx,sum[i]);
else for(R int i=n-1;i>0;i-=2)cmax(mx,sum[i]);
printf("%lld
",res+mx);
}
return 0;
}
(INTRPATH)
首先两条路径有交说明其中一个(LCA)在另一个上面。如果((a,b))和((u,v))交于(w)上,(w)必定是(LCA(a,b))或(LCA(u,v))
树剖,对于(w)是(LCA(a,b))的情况,每个节点上记录不同时经过(u)和(u)的重儿子的简单路径的条数,然后做个前缀和。跳到另一条重链上的时候特殊处理一下,(LCA)上特殊处理一下
对于(w)是(LCA(u,v))的情况,计算一下跨过这棵子树的路径条数就可以了
//quming
#include<bits/stdc++.h>
#define R register
#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;}
template<class T>inline bool cmin(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;
}
typedef long long ll;
const int N=3e5+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],rk[N],sz[N],fa[N],dep[N],top[N],son[N];ll f[N],g[N],sum[N];
int n,tim,q,T;
inline void swap(R int &x,R int &y){R int t=x;x=y,y=t;}
void dfs1(int u){
sz[u]=1,dep[u]=dep[fa[u]]+1,f[u]=1,son[u]=0;
go(u)if(v!=fa[u]){
fa[v]=u,dfs1(v),f[u]+=1ll*sz[v]*sz[u],sz[u]+=sz[v];
if(sz[v]>sz[son[u]])son[u]=v;
}
g[u]=1ll*(sz[u]-sz[son[u]])*sz[son[u]],f[u]-=g[u];
}
void dfs2(int u,int t){
top[u]=t,sum[dfn[u]=++tim]=f[u];
if(!son[u])return;dfs2(son[u],t);
go(u)if(v!=fa[u]&&v!=son[u])dfs2(v,v);
}
int jump(int u,int lca){
int tmp=0;
while(top[u]!=top[lca])tmp=top[u],u=fa[tmp];
return sz[u==lca?tmp:son[lca]];
}
ll query(int u,int v){
if(u==v)return f[u]+g[u]+1ll*sz[u]*(n-sz[u]);
ll res=0;int x=u,y=v,lca,si;ll s;
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v);
u=fa[top[u]];
}
lca=dep[u]<dep[v]?u:v,u=x,v=y;
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v);
res+=sum[dfn[u]]-sum[dfn[top[u]]-1],u=top[u];
if(fa[u]!=lca)res+=g[fa[u]]-1ll*sz[u]*(sz[fa[u]]-sz[u]);
u=fa[u];
}
if(dep[u]<dep[v])swap(u,v);
res+=sum[dfn[u]]-sum[dfn[v]];
u=x,v=y,x=y=0;
if(u!=lca)res+=g[u],x=jump(u,lca);
if(v!=lca)res+=g[v],y=jump(v,lca);
s=f[lca]+g[lca],si=sz[lca],s-=1ll*x*(si-x),si-=x,s-=1ll*y*(si-y);
res+=s,res+=1ll*(sz[lca]-x-y)*(n-sz[lca]);
return res;
}
inline void clr(){memset(head,0,(n+1)<<2),memset(fa,0,(n+1)<<2),tot=tim=0;}
int main(){
// freopen("testdata.in","r",stdin);
for(T=read();T;--T){
n=read(),q=read();
for(R int i=1,u,v;i<n;++i)u=read(),v=read(),add(u,v),add(v,u);
dfs1(1),dfs2(1,1);
fp(i,1,n)sum[i]+=sum[i-1];
for(R int u,v;q;--q)u=read(),v=read(),printf("%lld
",query(u,v));
clr();
}
return 0;
}
(COOLCHEF)
某位大佬:复杂度算啥能过就行
简单来说就是用(vector)存下每个数的出现位置,然后每一个询问暴力二分就可以了……我也不知道为什么能过……唯一的剪枝就是把总共出现次数只有一次的去掉……
//minamoto
#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)
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=3e5+5,P=1e9+7;
inline void swap(R int &x,R int &y){R int t=x;x=y,y=t;}
inline void upd(R int &x,R int y){(x+=y)>=P?x-=P:0;}
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
R int res=1;
for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
return res;
}
vector<int>pos[N];int top,n,q,ans,m;
int fac[N],ifac[N],b[N],a[N],sz[N],bg[N],ed[N],st[N];
int main(){
// freopen("testdata.in","r",stdin);
n=read(),q=read();
fp(i,1,n)a[i]=b[i]=read();
fac[0]=ifac[0]=1;fp(i,1,n)fac[i]=mul(fac[i-1],i);
ifac[n]=ksm(fac[n],P-2);fd(i,n-1,1)ifac[i]=mul(ifac[i+1],i+1);
sort(b+1,b+1+n),m=unique(b+1,b+1+n)-b-1;
fp(i,1,n)a[i]=lower_bound(b+1,b+1+m,a[i])-b,pos[a[i]].push_back(i);
fp(i,1,m)if(pos[i].size()>1)
st[++top]=i,bg[top]=pos[i].front(),ed[top]=pos[i].back();
for(R int l1,l2,r1,r2,l,r,c;q;--q){
l1=read(),l2=read(),r1=read(),r2=read();
l=(1ll*l1*ans+l2)%n+1,r=(1ll*r1*ans+r2)%n+1;
if(l>r)swap(l,r);
ans=1;
fp(i,1,top)if(bg[i]<=r&&ed[i]>=l){
c=upper_bound(pos[st[i]].begin(),pos[st[i]].end(),r)
-lower_bound(pos[st[i]].begin(),pos[st[i]].end(),l);
ans=mul(ans,ifac[c]);
}
ans=mul(ans,fac[r-l+1]);
printf("%d
",ans);
}
return 0;
}
(COUNTIT)
为了方便把前(n)个数记为(a_i),后(m)个数记为(b_i)
可以证明,当且仅当(max(a_i)=max(b_i))一定是一组合法解(如果不想看证明的可以直接跳过)
必要性很显然。对于充分性,假设(a_i)和(b_i)的最大值都只有一个,那么把除了这一行一列之外的其他数都设为(1),这一行一列的数调整到满足对应行列的需求。如果有多个最大值同理
所以答案就是
后面展开是一个(n+m)次多项式,前缀和是一个(n+m+1)次多项式,拉格朗日插值就行了
代码还没调出来再等等
好吧原来是拉格朗日插值打错了……
//minamoto
#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)
using namespace std;
const int P=1e9+7;
inline void upd(R int &x,R int y){(x+=y)>=P?x-=P:0;}
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
R int res=1;
for(;y;y>>=1,x=mul(x,x))if(y&1)res=mul(res,x);
return res;
}
const int N=5e5+5;
int fn[N],fm[N],f[N],fac[N],ifac[N],Pre[N],suf[N],n,m,p,T,c;
int Lagrange(int n,int k){
if(k<=n)return f[k];
Pre[0]=1;fp(i,1,n)Pre[i]=mul(Pre[i-1],k-i);
suf[n+1]=1;fd(i,n,1)suf[i]=mul(suf[i+1],k-i);
int res=0,ty=(n&1)?1:P-1;
fp(i,1,n)upd(res,1ll*f[i]*ty%P*Pre[i-1]%P*suf[i+1]%P*ifac[i-1]%P*ifac[n-i]%P),ty=P-ty;
return res;
}
int main(){
// freopen("testdata.in","r",stdin);
int t=2e5+10;
fac[0]=ifac[0]=1;fp(i,1,t)fac[i]=mul(fac[i-1],i);
ifac[t]=ksm(fac[t],P-2);fd(i,t-1,1)ifac[i]=mul(ifac[i+1],i+1);
for(scanf("%d",&T);T;--T){
scanf("%d%d%d",&n,&m,&p),c=n+m+5;
fn[0]=fm[0]=0;
fp(i,1,c)fn[i]=ksm(i,n);
fp(i,1,c)fm[i]=ksm(i,m);
fp(i,1,c)f[i]=mul(dec(fn[i],fn[i-1]),dec(fm[i],fm[i-1]));
fp(i,1,c)upd(f[i],f[i-1]);
printf("%d
",Lagrange(c,p));
}
}
(FGTREE)
七月月赛都开了我才补完六月的……
我们对于(dfs)序从小到大考虑,维护一个栈,表示的是从根节点到当前节点的这条链,对于新的节点,如果还在这条链上就加入,否则说明之前有一些节点可以出栈了,那么就可以顺便更新左边界和他们的父亲
//minamoto
#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)
using namespace std;
const int N=105;
int fa[N],l[N],st[N],top,n,T;
bool ask(int x,int l,int r){
printf("Q %d %d %d
",x,l,r),fflush(stdout);
char s[5];scanf("%s",s);return s[0]=='Y';
}
int main(){
for(scanf("%d",&T);T;--T){
scanf("%d",&n),top=0;
memset(fa,-1,(n+1)<<2);
fp(i,1,n){
int las=0;
while(top&&ask(st[top],l[st[top]],i-1)){
if(las)fa[las]=st[top];
las=st[top--];
}
las?(fa[las]=i,l[i]=l[las]):l[i]=i;
st[++top]=i;
}
while(top>1)fa[st[top]]=st[top-1],--top;
putchar('A');
fp(i,1,n)printf(" %d",fa[i]);
puts(""),fflush(stdout);
}
return 0;
}