A.求和
link
A.求和
大致意思就是求
solve
这题我们要从模的本质出发:
我们首先不考虑(i eq j)条件,单独对(i)或(j)讨论,我们可以得到
化简一下,可以得到
由与(lfloor frac{n}{i} floor)不同的只有(sqrt{n})个,这个式子可以(O(sqrt{n}))计算。对于(i),(j)分别做一遍相乘起来即可。
对于(i=j)的部分,单独拿出来减去贡献即可。我们用类似的方法,即求
然后跟之前一样的处理方法化为求
稍微化简一下就可以也(sqrt{n})分块了
最后相减就好了
code
#include<iostream>
#include<cstdio>
#define ll long long
#define MO 19940417
#define si 3323403
using namespace std;
ll n,m,Sn,Sm,S3,Ans;
ll Mod(ll x){
if (x<0) return x+MO;
if (x>=MO) return x-MO;
return x;
}
int main(){
scanf("%lld%lld",&n,&m);
if (n>m) swap(n,m);
Sn=n*n%MO;Sm=m*m%MO;S3=Sn*m%MO;
for (ll i=1,j;i<=n;i=j+1){
j=min(n,n/(n/i));
Sn=Mod(Sn-(n/i)*((i+j)*(j-i+1)/2%MO)%MO);
}
for (ll i=1,j;i<=m;i=j+1){
j=min(m,m/(m/i));
Sm=Mod(Sm-(m/i)*((i+j)*(j-i+1)/2%MO)%MO);
}
for (ll i=1,j;i<=n;i=j+1){
j=min(n,min(n/(n/i),m/(m/i)));
S3=Mod(S3-(m/i*n+n/i*m)%MO*((i+j)*(j-i+1)/2%MO)%MO+(n/i)*(m/i)%MO*Mod(j*(j+1)%MO*(2*j+1)%MO-(i-1)*i%MO*(2*i-1)%MO)%MO*si%MO);
}
printf("%lld
",Mod(Sn*Sm%MO-S3));
return 0;
}
B.排队
link
solve
看到这道题,第一反应就是这个关系是一棵树
对于每一个节点的不同儿子,先后顺序有着很大的影响,为了消除这种影响,我们先进行一道转化,先可以把比 (x_i) 级别小的所有节点都插入到 (x_i) 的子树中,这样就方便统计了。
如果一个结点有两个儿子l,r,并且l排在r的前面,那么总的方法数就是(f[l]*f[r]*C(size[l]+size[r],size[l]-1))
其含义是:容易想到,根据乘法原理,总共会有(f[l]*f[r])种情况,对于每种情况,都可以有(C(size[l]+size[r],size[l]-1))种合并方法
子树总共有(size[l]+size[r])个结点(不算根结点),所以空的位置就是(size[l]+size[r])个,其中属于(l)的总共就有(size[l]-1)个,这个就直接用组合数就算出来了
然后再一个个往后合并就好了
code
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int TT=10007;
const int maxn=1005,maxe=2005;
int N,lnk[maxn],nxt[maxe],son[maxe],cnt,size[maxn],F[maxn],T,C[maxn<<1][maxn<<1],lst;
inline int read(){
int ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
return ret*f;
}
inline void add_e(int x,int y){son[++cnt]=y;nxt[cnt]=lnk[x];lnk[x]=cnt;}
void DFS(int x){
size[x]=1;F[x]=1;
for(int j=lnk[x];j;j=nxt[j]){
DFS(son[j]);
size[x]+=size[son[j]];
F[x]=F[x]*(F[son[j]])%TT;
if(j!=lnk[x])F[x]=(F[x]*C[size[x]-1][size[son[j]]])%TT;
}
return ;
}
int main(){
// freopen("c.in","r",stdin);
// freopen("c.out","w",stdout);
T=read();
C[0][0]=1;
for(int i=1;i<=2000;i++)
for(int j=0;j<=2000;j++)C[i][j]=i==j||j==0?1:(C[i-1][j]+C[i-1][j-1])%TT;
while(T--){
cnt=0;
memset(F,0,sizeof F);
memset(lnk,0,sizeof lnk);
memset(nxt,0,sizeof nxt);
memset(son,0,sizeof son);
memset(size,0,sizeof size);
N=read();
for(int i=1;i<=N;i++){
int p=read();lst=i;
for(int j=1;j<=p;j++){
int x=read();
add_e(lst,x);lst=x;
}
}
DFS(1);
printf("%d
",F[1]);
}
return 0;
}
C.城市
link
solve
仔细读这道题,我们发现就是找一个环上点的最大值最小值。
显然,贪心的想法,我们先建一颗最小生成树,然后我们再加一条边就变成一个环了,我们加边也由小到大来加
每加一条边,我们就要将边所对应的的两个点在树上的路径赋成这条边的权值,但是这样显然是超时的,要考虑怎么优化。
我们可以用并查集来链接,这样就能保证每条边的遍历次数大大减小
对于询问,每两个点之间的最大权值,我们用LCA来维护,当我们查询时发现x和y不连通,即是无解。
#include<cstdio>
#include<cctype>
#include<algorithm>
const int maxn=100005,maxe=500005;
int n,m,q,w[maxn],lgn;struct Y{int x,y,z;}e[maxe];
int fa[maxn],pa[maxn][20],dep[maxn],f[maxn][20];
int son[maxn<<1],lnk[maxn],lst[maxn<<1],tot;bool vis[maxe];
inline int red(){
int ret=0;char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) ret=(ret<<3)+(ret<<1)+(ch^48),ch=getchar();
return ret;
}
inline int abs_(int x){return x>0? x:-x;}
inline bool cmp(Y x,Y y){return x.z<y.z;}
inline int max_(int x,int y){return x>y? x:y;}
int gt(int x){return x==fa[x]? x:fa[x]=gt(fa[x]);}
inline int lg(int x){int r=-1;while(x) r++,x>>=1;return r;}
inline void e_(int x,int y){son[++tot]=y;lst[tot]=lnk[x];lnk[x]=tot;}
void DFS(int x){
for(int j=lnk[x];j;j=lst[j]) if(son[j]!=pa[x][0])
dep[son[j]]=dep[x]+1,pa[son[j]][0]=x,DFS(son[j]);
}
inline int LCA(int x,int y){
int ret=0;
if(dep[x]<dep[y]) x^=y^=x^=y;
for(int i=lgn;~i;i--){
if(dep[pa[x][i]]>=dep[y])
ret=max_(ret,f[x][i]),x=pa[x][i];
if(x==y) return ret;
}
for(int i=lgn;~i;i--) if(pa[x][i]!=pa[y][i])
ret=max_(ret,max_(f[x][i],f[y][i])),x=pa[x][i],y=pa[y][i];
return max_(ret,max_(f[x][0],f[y][0]));
}
int main(){
n=red(),m=red(),q=red();lgn=lg(n);
for(int i=1;i<=n;i++) w[fa[i]=i]=red();
for(int i=1,x,y;i<=m;i++){
x=red(),y=red();
e[i]=(Y){x,y,abs_(w[x]-w[y])};
}
std::sort(e+1,e+1+m,cmp);
for(int i=1,fx,fy;i<=m;i++){
fx=gt(e[i].x);fy=gt(e[i].y);
if(fx==fy){vis[i]=1;continue;}
fa[fx]=fy;e_(e[i].x,e[i].y);e_(e[i].y,e[i].x);
}
DFS(1);
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1,x,y;i<=m;i++) if(vis[i]){
x=gt(e[i].x),y=gt(e[i].y);
while(x!=y){
if(dep[x]<dep[y]) x^=y^=x^=y;
f[x][0]=e[i].z;x=fa[x]=gt(pa[x][0]);
}
}
for(int j=1;j<=lgn;j++) for(int i=1;i<=n;i++)
pa[i][j]=pa[pa[i][j-1]][j-1],f[i][j]=max_(f[i][j-1],f[pa[i][j-1]][j-1]);
for(int x,y;q--;){
x=red();y=red();
if(gt(x)!=gt(y)) printf("infinitely
");
else printf("%d
",LCA(x,y));
}
return 0;
}