AFO

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);
}
posted @ 2019-09-16 11:38  ZUTTER☮  阅读(132)  评论(0编辑  收藏  举报