T1
这是一个更相减损。
出现的所有的不同的数就是更相减损过程中出现的;
直接这样做的话,会T或者爆;
再进一步分析一下,就会发现,我们可以把更相减损优化为辗转相除,因为多几次更相减损就是辗转相除,那么不同数的个数在辗转相除中就是每次的a/b,因为a只有减损a/b次才会达到b,a%b的状态,这之间的数是递减的,不会出现重复。
T2
50分,我们可以倒着加边,添加进新的边时,用并查集维护,合并集合时,把每个集合新加进的点的个数记下来,这一轮结束后,ans[i]+=ad[i]*ad[i]就可以了。
100分:
用克鲁斯卡尔算法求最大生成树,在并查集合并时,把原本的一个根连向另一
个根改成两个根都连向一个新建的节点,并把当前正在处理的边的权值赋给这
个新节点做点权。这样形成的结构会是一棵树。
一个点的答案大致上是树的根到自己的路径上,相邻两个节点的子树叶节
点数的平方和。需要注意的是父子两个节点权值相同的情况,这个部分需要特
殊处理。(看代码会比较容易理解)
T3
不是太会。
T1
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
LL a1,a2,ans;
LL gcd(LL a,LL b)
{
if(!b) return a;
ans+=a/b;
return gcd(b,a%b);
}
int main()
{
freopen("seq.in","r",stdin);
freopen("seq.out","w",stdout);
scanf("%lld%lld",&a1,&a2);
if(a1<a2) swap(a1,a2);
gcd(a1,a2);
ans++;//0也算一种
printf("%lld\n",ans);
return 0;
}
T2
50分
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#define LL long long
using namespace std;
const int N=100009;
const int M=200009;
const int inf=(1e9);
int n,m;
struct H{
int x,y,z;
}e[M];
int a[M],cnt,f[N];
LL ans[N],siz[N],ad[N];
bool cmp(H w1,H w2)
{
return w1.z>w2.z;
}
int find(int x)
{
return f[x]==x?x:f[x]=find(f[x]);
}
void add(int o)
{
int fx=find(e[o].x);
int fy=find(e[o].y);
if(fx!=fy)
{
for(int i=1;i<=n;i++)
{
int ff=find(i);
if(ff==fx)
ad[i]+=siz[fy];
else
if(ff==fy)
ad[i]+=siz[fx];
}
f[fx]=fy;
siz[fy]+=siz[fx];
}
}
int main()
{
freopen("car.in","r",stdin);
freopen("car.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].z);
sort(e+1,e+m+1,cmp);
for(int i=1;i<=m;i++) if(e[i].z!=a[cnt]) a[++cnt]=e[i].z;
for(int i=1;i<=n;i++) f[i]=i,siz[i]=1;
int t=1;
for(int i=1;i<=cnt;i++)
{
int flag=0;
while(e[t].z>=a[i]&&t<=m)
{
add(t);
t++;
flag=1;
}
if(f)
for(int i=1;i<=n;i++)
{
ans[i]+=ad[i]*ad[i];
ad[i]=0;
}
if(t>m) break;
}
for(int i=1;i<=n;i++)
printf("%lld ",ans[i]);
return 0;
}
100分(打了一遍找不到了,贴标程吧qaq)
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N = 510000;
typedef long long ll;
struct node
{
int u, v, l;
bool operator < (const node &no) const
{
return l > no.l;
}
}e[N];
int n, m, newn;
int son[N][2];
int fa[N], size[N], value[N];
ll ans[N];
int read()
{
char ch = getchar();
int x = 0;
while (!isdigit(ch)) ch = getchar();
while (isdigit(ch)) {x = x*10+(ch-'0');ch=getchar();}
return x;
}
int getf(int x)
{
if (fa[x] == x) return x;
fa[x] = getf(fa[x]);
return fa[x];
}
void dfs(int u, int fa, ll cnt)
{
ll delta = 0;
if (fa)
{
if (value[u] == value[fa]) size[u] = size[fa];
else delta = (ll)(size[fa] - size[u]) * (ll)(size[fa] - size[u]);
}
if (son[u][0])
{
dfs(son[u][0], u, cnt + delta);
dfs(son[u][1], u, cnt + delta);
}
else ans[u] = cnt + delta;
}
int main()
{
freopen("car.in","r",stdin);
freopen("car.out","w",stdout);
n = read(), m = read();
for (int i = 1; i <= m; i++)
{
e[i].u = read();
e[i].v = read();
e[i].l = read();
}
sort(e + 1, e + 1 + m);
for (int i = 1; i <= n; i++) fa[i] = i;
newn = n;
for (int i = 1; i <= n; i++) size[i] = 1;
for (int i = 1; i <= m; i++)
{
int u = getf(e[i].u), v = getf(e[i].v);
if (u == v) continue;
newn++;
son[newn][0] = u;
son[newn][1] = v;
fa[u] = fa[v] = newn;
fa[newn] = newn;
value[newn] = e[i].l;
size[newn] = size[u] + size[v];
}
dfs(newn, 0, 0);
for (int i = 1; i <= n; i++)
printf("%lld ", ans[i]);
printf("\n");
return 0;
}