Codeforces Round 911 (Div. 2)
比赛录屏
https://www.bilibili.com/video/BV1H34y1F7B1/
\(A. Cover in Water\)
https://codeforces.com/contest/1900/submission/234430348
\(B. Laura and Operations\)
https://codeforces.com/contest/1900/submission/234447465
\(C. Anji's Binary Tree\)
https://codeforces.com/contest/1900/submission/234455131
\(D. Small GCD\)
题意:定义 \(f(x,y,z)\) 为其中较小的两数字的 \(gcd\) ,求一个数组的 \(\sum _{i=1}^{n}\sum _{j=i+1}^{n}\sum _{k=j+1}^{n} f(a_i,a_j,a_k)\) 。
解法:赛场很容易观察到:答案与数组的顺序无关,所以我们从小到大排序容易计算任两对的状态。然后就陷入僵局了,我并不知道如何处理 \(gcd\) 。
对于两个数字的 \(gcd\) ,我们可以把 \(gcd\) 的贡献分给较大数字的约数。例如 \(16\) 与 \(8\) 的 \(gcd\) 是 \(8\) ,我们可以看作是 \(16\) 的约数 \(1,2,4,8,16\) 的和贡献。其中 \(1\) 的贡献为 \(1\) ,\(2\) 的贡献为 \(2-1\) ,\(4\) 的贡献为 \(4-1-1=2\) ,\(8\) 的贡献为 \(8-1-1-2-=4\) ,以此类推。我们可以发现我们本质其实是把 \(gcd\) 转化为对每个数的所有约数做一个前缀和,那么约数的约数要被去重。这样计算就是一个 \(O(\sum(a_i的约数个数))\) 的复杂度,由于 \(a_i\le 1e5\) ,并不大,所以复杂度并不高。
vector<int>divs[N];
int phi[N],a[N];
void solve(){
int n=read(),ans=0;
for(int i=1;i<=n;i++){
a[i]=read();
}
sort(a+1,a+1+n);
vector<int>cnt(N);
for(int i=1;i<=n;i++){
for(auto x:divs[a[i]]){
ans+=phi[x]*cnt[x]*(n-i);
cnt[x]++;
}
}
cout<<ans<<'\n';
//puts(ans>0?"YES":"NO");
//puts(ans>0?"Yes":"No");
}
signed main(){
// ios::sync_with_stdio(false);
// cin.tie(0);
// cout.tie(0);
for(int i=1;i<=100000;i++){
for(int j=i;j<=100000;j+=i){
divs[j].push_back(i);
}
}
for(int i=1;i<=100000;i++){
phi[i]=i;
}
for(int i=1;i<=100000;i++){
for(int j=2*i;j<=100000;j+=i){
phi[j]-=phi[i]; //
}
}
int t=read();
while(t--){
solve();
}
}
\(E. Transitive Graph\)
题意:给定一个有向图,有点权,重复进行如下操作:如果存在边 \(a\rightarrow b\rightarrow c\) 则加边 \(a\rightarrow c\) 。询问点权之和最小且经过点数最多的简单路径的长度以及点权之和。
解法:首先,对于强联通分量,我们必然能找出一条路径经过所有点得到一条最长路。如果有一条边指向强联通时,我们可以利用题目的操作仍然遍历整个强联通分量。所以变了一个含若干强联通分量的拓扑图上的最长且点权最小的点,显然的 \(dp\) 可以完成这个操作。
int cnt,low[N],num[N],dfn,sccno[N],sta[N],top;
vector<int>G[N],tp[N];
void dfs(int u){
sta[top++]=u;
low[u]=num[u]=++dfn;
for(int i=0;i<G[u].size();i++){
int v=G[u][i];
if(!num[v]){
dfs(v);
low[u]=min(low[v],low[u]);
}else if(!sccno[v]){
low[u]=min(low[u],num[v]);
}
}
if(low[u]==num[u]){
cnt++;
while(1){
int v=sta[--top];
sccno[v]=cnt;
if(u==v)break;
}
}
}
void Tarjan(int n){
cnt=top=dfn=0;
for(int i=0;i<=n;i++){
sccno[i]=num[i]=low[i]=0;
}
// memset(sccno,0,sizeof sccno);
// memset(num,0,sizeof num);
// memset(low,0,sizeof low);
for(int i=1;i<=n;i++){
if(!num[i]){
dfs(i);
}
}
}
void solve(){
int n=read(),m=read();
vector<int>a(n+1);
for(int i=1;i<=n;i++){
G[i].clear();
tp[i].clear();
a[i]=read();
}
for(int i=1;i<=m;i++){
G[read()].push_back(read());
}
Tarjan(n);
vector<PII>info(cnt+1),f(cnt+1);
for(int i=1;i<=n;i++){
info[sccno[i]].first++;
info[sccno[i]].second-=a[i];
for(auto x:G[i]){
if(sccno[i]!=sccno[x])tp[sccno[i]].push_back(sccno[x]);
}
}
for(int i=cnt;i>=1;i--){
f[i].first+=info[i].first;
f[i].second+=info[i].second;
for(auto x:tp[i]){
f[x]=max(f[x],f[i]);
}
}
auto ans=*max_element(f.begin(),f.end());
cout<<ans.first<<" "<<-ans.second<<'\n';
//puts(ans>0?"YES":"NO");
//puts(ans>0?"Yes":"No");
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
// int t=1;
int t=read();
while(t--){
solve();
}
}

浙公网安备 33010602011771号