CF1179D
CF1179D
树形dp
基环树上的不在环上的每棵子树内的两个节点间只有一条路径,其他的是两条
然后就可以dp的找环上路径
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
const int M = 1100001;
const LL inf= 9999999999999999ll;
int head[M],n,m,k,cnt,x,y,ver[M],edge[M],nex[M],s[M],fr[M][2];
LL d[M][2],res=inf;
void add(int x,int y)
{
ver[++cnt]=y, nex[cnt]=head[x], head[x]=cnt;
ver[++cnt]=x, nex[cnt]=head[y], head[y]=cnt;
}
void dfs_(int x,int fa)
{
s[x]=1;
for(int i=head[x];i;i=nex[i])
{
if(ver[i]==fa) continue;
dfs_(ver[i],x);
s[x]+=s[ver[i]];
}
}
void dfs(int x,int fa)
{
if(s[x]==1) return;
d[x][0]=d[x][1]=inf;
for(int i=head[x];i;i=nex[i])
{
if(ver[i]==fa) continue;
dfs(ver[i],x);
LL k=d[ver[i]][0]+((LL)s[x]-s[ver[i]]-1)*((LL)s[x]-s[ver[i]])/2;
if(k<d[x][1])
{
d[x][1]=k;
fr[x][1]=ver[i];
}
if(d[x][1]<d[x][0])
{
swap(d[x][1],d[x][0]);
swap(fr[x][1],fr[x][0]);
}
}
res=min(res,d[fr[x][0]][0]+d[fr[x][1]][0]+((LL)n-s[fr[x][0]]-s[fr[x][1]])*((LL)n-s[fr[x][0]]-s[fr[x][1]]-1)/2);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
}
dfs_(1,0);
dfs(1,0);
printf("%I64d",(LL)n*n-n-res);
}
CF1208G
选一个比x小的且不与x互质的数肯定不会使答案变劣
选m相当于选了\(0,\frac1m,\frac2m\frac3m,...,\frac{m-1}m\)这些点,如果有的点可以约分,那它一定已经存在了
所以选x的贡献就是\(\varphi(x)\)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
const int M = 5000001;
int n,m,k,ph[M],p[M],P,b[M];
LL res;
void Ph(int n)
{
ph[1]=1;
for(int i=2;i<=n;i++)
{
if(!b[i]) p[++P]=i, ph[i]=i-1;
for(int j=1;j<=P && p[j]*i<=n;j++)
{
b[i*p[j]]=1;
if(i%p[j]==0)
{
ph[i*p[j]]=ph[i]*p[j];
break;
}
ph[i*p[j]]=ph[i]*(p[j]-1);
}
}
}
int main()
{
scanf("%d%d",&n,&m);
if(m==1)
{
printf("3");
return 0;
}
Ph(n);
sort(ph+1,ph+1+n);
for(int i=3;i<=m+2;i++) res+=(LL)ph[i];
printf("%lld",res+2ll);
}