noip2026模拟赛01题解
莫春者(muchun)
考虑拆贡献。由于 \(\sum_{i=1}^n\deg_i=2m\),所以不同的 \(\deg\) 种类只有至多 \(\sqrt{2m}\) 种。于是统计每种 \(\deg\) 出现的次数,枚举 \(\deg\) 计算即可,时间复杂度 \(O(m)\)。
忆追(llacer)
走一条边实际上就是增加或减少一个素因子。于是可以先把结论猜出来:即从 \(u\) 变到 \(v\) ,需经过 \(\gcd(u,v)\) 中转。也就是 \(u \to \gcd(u,v) \to v\) 。走的过程中只要不走回头路就能保证路径最短。
接下来计数即可,考虑 \(u \to \gcd(u,v)\) 的路径,就等价于 \(\frac{u}{\gcd(u,v)}\to 1\) 的路径。可以通过调整每次走哪个素因子来得到不同的最短路走法,问题转化为 \(\frac{u}{\gcd(u,v)}\) 的素因子的可重排列。由对称性, \(\gcd(u,v) \to v\) 的处理同理。最后两边方案乘起来。
实现的时候,一开始就把质因数做预处理,并且只需要分解 \(D\) 的素因数。因为 \(u,v\) 一定是 \(D\) 的因数,所以 \(u,v\) 的素因数一定是 \(D\) 的素因数。可以用 \(O(n^{\frac{1}{3}})\) 大概估计一个数 \(n\) 的因数个数,而素因数个数一定更小,所以 \(D\) 的素因数个数一定远远小于 \(10^5\)。
繁殖菌(mushroom)
先将字符串离散化成数字,然后就转化为了数颜色问题,这个问题在序列上做是简单的。
接下来想如何把树上问题转化为序列上的的问题。由于问的节点是跟深度有关,所以我们考虑先处理出树的 bfs 序。因为在 bfs 序上,同一深度的点是连续的。所以询问就变成了序列上区间数颜色的问题,用莫队解决就好了。
然后想如何快速的定位区间,我们需要在至多 \(O(\log^2 n)\) 的时间内定位出查询区间,容易想到一种暴力求法,就是在 bfs 的时候记录下每一个深度的起始位置和结束位置,对于需要查询的深度,从起始位置开始,找到第一个属于子树 \(u\) 的 \(v\) ;从结束位置开始,找到最后一个属于子树 \(u\) 的 \(v\)。这样定位显然是会超时的。
怎么优化呢?想一想,我们的询问除了深度的约束,还有子树的约束,而一棵子树中所有的点在 dfs 序下是连续的。于是可以这样做,求一遍 dfs 序,对于同一深度的节点,用同一个容器来维护他们的 dfs 序(比如存在一个 vector 里),同时记录每棵子树第一个 dfs 到的元素的 dfs 序和最后一个的 dfs 序。二分定位即可。单次定位复杂度 \(O(\log n)\)。
之后就是莫队了。在 \(n,m\) 同阶的情况下,时间复杂度为 \(O(n \log n + n \sqrt n)\)。
执念之地(cling)
事实上 \(l\) 并没有用,可以将区间缩成 \([0,1]\) 来考虑,最后答案乘上 \(l\) 即可
考虑一个点 \(x\) 被至少 \(k\) 条直线覆盖的概率,是
于是答案就是对其积分:
对 \((1-2x(1-x))^{n-i}\) 做二项式展开,得
代回原式,交换求和与积分顺序得
整理积分部分得
注意到这是第一类欧拉积分(贝塔积分)的形式,化得
代回原式得
此时已经可以 \(O(n^2)\) 做。但对于此题 \(n \le 10^5\) 的部分,考虑继续优化。
注意到
所以可以考虑改为枚举 \(i+j\),则求和式子变为
化简后面的求和
于是,我们得到了一个可以 \(O(n)\) 算的式子
预处理阶乘、逆元、\(2\) 的若干次幂,时间复杂度线性。
注意最后答案要乘上一开始忽略的 \(l\)。
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define int long long
using namespace std;
const int N=2e5+10,mod=1e9+7;
int n,m,tot,ans;
vector<int> g[N];
int a[N],cnt[N],du[N];
map <int,int> mp;
int f(int x,int y){
return (x^y)*(x|y)%mod*(x&y)%mod;
}
signed main(){
freopen("muchun.in","r",stdin);
freopen("muchun.out","w",stdout);
scanf("%lld%lld",&n,&m);
while(m--){
int u,v;
scanf("%lld%lld",&u,&v);
du[u]++,du[v]++;
}
rep(i,1,n){
if(mp.find(du[i])==mp.end()){
tot++;
mp[du[i]]=tot;
cnt[tot]++;
a[tot]=du[i];
}
else cnt[mp[du[i]]]++;
}
rep(i,1,tot) rep(j,i+1,tot) ans=(ans+f(a[i],a[j])*(cnt[i]*cnt[j]%mod)%mod)%mod;
cout<<ans;
return 0;
}
#include <bits/stdc++.h>
#define mp make_pair
#define gcd __gcd
#define int long long
#define itt int
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b,c) for(int i=(a);i<=(b);i+=(c))
#define per(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
const int N=3e5+10,mod=998244353;
itt d,n,q,cnt,cnt1[N],cnt2[N];
int fact[N/100]={1},inv[N/100]={1},prime[N];
int ksm(int a,int b){
int s=1;
while(b){
if(b&1) s=a*s%mod;
b>>=1,a=a*a%mod;
}
return s%mod;
}
signed main(){
freopen("llacer.in","r",stdin);
freopen("llacer.out","w",stdout);
cin>>d>>q;
rep(i,1,100) fact[i]=fact[i-1]*i%mod;
inv[100]=ksm(fact[100],mod-2);
per(i,99,1) inv[i]=inv[i+1]*(i+1)%mod;
int tmp=d;
rep(i,2,d/i+1){
if(tmp%i==0) prime[++cnt]=i;
while(tmp%i==0) tmp/=i;
}
if(tmp>1) prime[++cnt]=tmp;
rep(cas,1,q){
int u,v,x;
scanf("%lld%lld",&u,&v);
x=gcd(u,v);
u/=x,v/=x;
int I=0,J=0,U=u,V=v,i=0,j=0;
rep(y,1,cnt){
int k=prime[y];
if(u%k==0) i++;
while(u%k==0){
I++;
cnt1[i]++;
u/=k;
}
}
rep(y,1,cnt){
int k=prime[y];
if(v%k==0) j++;
while(v%k==0){
J++;
cnt2[j]++;
v/=k;
}
}
int ans1=fact[I],ans2=fact[J];
rep(k,1,i) ans1=ans1*inv[cnt1[k]]%mod;
rep(k,1,j) ans2=ans2*inv[cnt2[k]]%mod;
printf("%lld\n",ans1*ans2%mod);
rep(k,1,i) cnt1[k]=0;
rep(k,1,j) cnt2[k]=0;
}
return 0;
}
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define mid (l+r)/2
using namespace std;
const int N=1e5+10;
int n,Q,root,max_col,max_dep,m,res,timer;
int a[N],col[N],dep[N],sta[N],ed[N],cnt[N],dfn[N],out[N];
struct query{
int L,R,ans,id,b;
}qu[N];
vector <int> g[N],b[N];
map <string,int> mp;
void dfs(int u,int fa){
dfn[u]=++timer;
dep[u]=dep[fa]+1;
if(b[dep[u]].size()==0) b[dep[u]].push_back(-1);
b[dep[u]].push_back(dfn[u]);
for(auto v:g[u]) dfs(v,u);
out[u]=timer;
return ;
}
void bfs(int st){
queue <int> q;
stack <int> s;
q.push(st);
while(!q.empty()){
int u=q.front();
max_dep=max(max_dep,dep[u]);
a[++m]=u;
if(!sta[dep[u]]) sta[dep[u]]=m;
if(!ed[dep[u]-1]) ed[dep[u]-1]=m-1;
for(auto v:g[u]) q.push(v);
q.pop();
}
ed[max_dep]=m;
}
bool cmp1(query A,query B){
if(A.L!=B.L) return A.L<B.L;
else return A.b<B.b;
}
bool cmp2(query A,query B){
return A.id<B.id;
}
void add(int x){
cnt[a[x]]++;
if(cnt[a[x]]==1) res++;
}
void del(int x){
cnt[a[x]]--;
if(cnt[a[x]]==0) res--;
}
int getL(int z,int u){
return lower_bound(b[z].begin()+1,b[z].end(),dfn[u])-b[z].begin()-1;
}
int getR(int z,int u){
return upper_bound(b[z].begin()+1,b[z].end(),out[u])-b[z].begin()-2;
}
int main(){
freopen("mushroom.in","r",stdin);
freopen("mushroom.out","w",stdout);
scanf("%d",&n);
int len=sqrt(n);
rep(i,1,n){
string s;
int fa;
cin>>s;
scanf("%d",&fa);
if(mp.find(s)==mp.end()) col[i]=++max_col,mp[s]=max_col;
else col[i]=mp[s];
g[fa].push_back(i);
}
col[0]=++max_col;
dfs(root,n+1);bfs(root);
scanf("%d",&Q);
rep(i,1,Q){
int u,k,z;
scanf("%d%d",&u,&k);
qu[i].id=i,z=dep[u]+k;
qu[i].L=sta[z]+getL(z,u);
qu[i].R=sta[z]+getR(z,u);
qu[i].b=(qu[i].R-1+len)/len;
}
sort(qu+1,qu+Q+1,cmp1);
int l=0,r=0;
rep(i,1,n+1)a[i]=col[a[i]];
rep(i,1,Q){
while(r<qu[i].R) add(++r);
while(l>qu[i].L) add(--l);
while(l<qu[i].L) del(l++);
while(r>qu[i].R) del(r--);
qu[i].ans=res;
}
sort(qu+1,qu+Q+1,cmp2);
rep(i,1,Q) printf("%d\n",qu[i].ans);
return 0;
}
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define int long long
using namespace std;
const int N=2e5+10,mod=998244353;
int pw[N]={1},fact[N]={1},inv[N]={1};
int ksm(int a,int b){
int s=1;
while(b){
if(b&1) s=a*s%mod;
a=a*a%mod;
b>>=1;
}
return s%mod;
}
void pre(int n){
rep(i,1,n){
fact[i]=fact[i-1]*i%mod;
pw[i]=pw[i-1]*2%mod;
}
inv[n]=ksm(fact[n],mod-2);
per(i,n-1,1) inv[i]=inv[i+1]*(i+1)%mod;
}
int c(int n,int m){
return fact[n]*inv[m]%mod*inv[n-m]%mod;
}
signed main(){
freopen("cling.in","r",stdin);
freopen("cling.out","w",stdout);
int n,k,l,ans=0;
pre(2e5+5);
cin>>n>>k>>l;
rep(i,k,n){
int flag;
if((i-k)%2) flag=-1ll;
else flag=1ll;
ans=(ans+flag*c(n,i)*c(i-1,i-k)%mod*pw[i]%mod*fact[i]%mod*fact[i]%mod*inv[2*i+1]%mod+mod)%mod;
}
cout<<ans*(l%mod)%mod;
return 0;
}

浙公网安备 33010602011771号