由于第二天还要上学,就没有去打/kk
赛后补了一下,结果E没在规定时间内A掉(我搞了场虚拟赛),F到是切掉了……自闭了。
Solution
A
水题,直接输出 2 , 3 , 4 … … , n , 1 2,3,4……,n,1 2,3,4……,n,1即可。
B
先跑出最小值,并且用一个桶记录数组中每个数是否出现过;最后扫一遍,找到等于最小值并且出现次数只有 1 1 1次的数即可。注意输出的是位置而不是值。
C
开 n n n个桶,每个桶里面维护的是很多个区间;更详细地说,第 i i i个桶中存下来了所有值都是 i i i的区间,用许多二元组表示。
然后对于每一个 k k k,求出这 k k k个区间将整个序列分成了多少块即可(这 k k k个区间不算在内)。
时间复杂度 O ( ∑ n ) O(\sum n) O(∑n)。
D
首先我们要发现一个性质: 若将答案序列从小到大排序,那么除去最后一个数外,其他的数都是 n n n的质因数中指数(幂次)最高的质因数 p p p,最后一个数是 n n n除以前面的所有数的乘积。
于是我们质因数分解,求出 p p p以及 p p p的最大指数质因数 t t t。答案序列就是 t − 1 t-1 t−1个 p p p与一个 n p t − 1 \frac n {p^{t-1}} pt−1n。
时间复杂度 O ( ∑ n ) O(\sum \sqrt n) O(∑n)。
E
一道基环树的比较套路的题目。
首先,我们用并查集将这唯一的一个环缩成一个点,定义这个点为环点 x x x。令 x x x为根。在此时形成的树中,如果去掉环点 x x x,对于剩下的所有子树内的任何两个节点,都只有一种到达方式,即不能经过多余的那一条边,否则形成的就不是一个简单路径。对于任何两个跨子树的节点对,或者有一个是 x x x的节点对都可以经过环,即多出现了一种走法。同时,对于环点 x x x与任何一个其他节点,也都只有一种到达方式。
假设对于 x x x的每一个儿子的子树大小为 s i z siz siz,那么答案就是
n ( n − 1 ) − ∑ ( s i z + 1 ) s i z 2 n(n-1)-\sum \frac {(siz+1)siz} 2 n(n−1)−∑2(siz+1)siz
可以这么理解: 假设任意两个点之间都有两种走法。那么的对于两个节点属于同一个子树的节点对就被多算了,要减去这种情况。
时间复杂度 O ( ∑ n log n ) O(\sum n \log n) O(∑nlogn)。当然如果你的并查集用了按秩合并(启发式合并)的优化,可以优化到 O ( ∑ n ) O(\sum n) O(∑n)。
F
为了方便叙述,这里的 x x x的定义与题目中的 x x x相同,但 y y y的定义变成了第三个段的左端点。
首先,我们枚举这个 x x x,并尝试快速求出 y y y。
我们处理前缀最大值与后缀最大值,并将后缀最大值用桶记录下来,第 i i i个桶记录下了所有后缀最大值为 i i i的位置。假设 1 − x 1-x 1−x的最大值为 a a a,那么后 y y y个数的最大值也必须为 a a a,即 y y y必须在第 a a a个桶中找。
考虑确定了 x x x后,如果 y y y单调向右,那么区间 [ x + 1 , y − 1 ] [x+1,y-1] [x+1,y−1]即第二段的最小值单调不增。而这个最小值也是确定的,所以我们可以二分。每次的 c h e c k check check,相当于静态的区间查询最小值,可以采用RMQ来解决。
综上所述,我们通过 v e c t o r vector vector内二分套上一个 R M Q RMQ RMQ,得到了复杂度为 O ( ∑ ( n log n ) ) O(\sum (n \log n)) O(∑(nlogn))的算法,可以轻松通过本题。
Code
A&&B&&C
咕咕咕
D
#include <bits/stdc++.h>
#define int long long
using namespace std;
int t,n;
signed main()
{
cin>>t;
while (t--)
{
cin>>n;
int maxv=0,pos=0,tot=n;
for (int i=2;i*i<=n;i++)
{
if (n%i==0)
{
int cnt=0;
while (n%i==0) n/=i,cnt++;
if (cnt>maxv) maxv=cnt,pos=i;
}
}
if (n>1)
{
int cnt=1;
if (cnt>maxv) maxv=cnt,pos=n;
}
cout<<maxv<<endl;
for (int i=1;i<=maxv-1;i++) cout<<pos<<' ',tot/=pos;
cout<<tot<<endl;
}
return 0;
}
E
#include <bits/stdc++.h>
#define int long long
using namespace std;
int read()
{
int s=0,w=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') w=-w;ch=getchar();}
while (ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+(ch%'0');ch=getchar();}
return s*w;
}
int t,n,cnt=0,u,v,root;
int head[200005],fa[200005],siz[200005],vis[200005],with[200005];
struct edge{int next,to;}e[400005];
void add_edge(int x,int y){cnt++;e[cnt].to=y,e[cnt].next=head[x],head[x]=cnt;}
void clear()
{
for (int i=1;i<=n;i++) head[i]=vis[i]=siz[i]=with[i]=0;
for (int i=1;i<=cnt;i++) e[i].to=e[i].next=0;
cnt=0;
}
int fin(int x)
{
if (x==fa[x]) return x;
else return fa[x]=fin(fa[x]);
}
void dfs(int now,int fath)
{
if (now==v) with[now]=1;
for (int i=head[now];i;i=e[i].next)
{
if (e[i].to!=fath)
{
dfs(e[i].to,now);
if (with[e[i].to]) with[now]=1;
}
}
}
void dfs2(int now,int fath)
{
vis[now]=1;
for (int i=head[now];i;i=e[i].next)
if (e[i].to!=fath&&with[e[i].to]) dfs2(e[i].to,now);
}
void dfs3(int now,int fath)
{
siz[now]=1;
for (int i=head[now];i;i=e[i].next)
{
int y=e[i].to;
if (y!=fath&&!vis[y])
dfs3(y,now),siz[now]+=siz[y];
}
}
signed main()
{
cin>>t;
while (t--)
{
cin>>n;
clear();
for (int i=1;i<=n;i++) fa[i]=i;
for (int i=1;i<=n;i++)
{
int x=read(),y=read();
int fx=fin(x),fy=fin(y);
if (fx!=fy)
add_edge(x,y),add_edge(y,x),fa[fx]=fy;
else u=x,v=y;
}
dfs(u,0);
dfs2(u,0);
int ans=n*(n-1);
for (int i=1;i<=n;i++)
if (vis[i]) dfs3(i,0),ans-=((siz[i]*(siz[i]-1))/2);
cout<<ans<<endl;
}
return 0;
}
F
#include <bits/stdc++.h>
#define int long long
using namespace std;
int t,n;
signed main()
{
cin>>t;
while (t--)
{
cin>>n;
int maxv=0,pos=0,tot=n;
for (int i=2;i*i<=n;i++)
{
if (n%i==0)
{
int cnt=0;
while (n%i==0) n/=i,cnt++;
if (cnt>maxv) maxv=cnt,pos=i;
}
}
if (n>1)
{
int cnt=1;
if (cnt>maxv) maxv=cnt,pos=n;
}
cout<<maxv<<endl;
for (int i=1;i<=maxv-1;i++) cout<<pos<<' ',tot/=pos;
cout<<tot<<endl;
}
return 0;
}