usaco 2018 jan contest gold

A:
题意:一张无向图,每次询问ki,vi计算从ki出发,只走边权大于vi的边,能到几条边。
思路:离线操作,先计算vi大的询问,询问前加上边权大于vi的边,用并查集计算。
B:
题意:一棵树,叶子节点是出口,牛从K点出发,在某些出口有村民抓牛,村民和牛的速度都是1,村民合理行动的情况下至少多少个村民能抓住牛。
思路:把K当做树根,每次牛一定往下走,考虑到一个点时,如果牛到他的距离比某一个叶子节点到他的距离长或相等,那么以这个点为根的子树只用一个人就够了,否则递归。
C:
题意:一横排n个格,有m种颜色的章,每个长度都是k,每个章可以用多次,涂色可以覆盖,不能涂到外面去,涂完色要求每个格都有色,问有最终有多少种图案。
思路:最后一个章一定让某处连续k个数有一样的颜色,其他的地方颜色随意。所以就是求长度为n的至少k个连续的格子颜色相同的方案数。可以通过求不存在连续k个格子颜色相同的个数来算。这样dp[i]表示长度是i的方案数,dp[i]可以由dp[i-k+1]到dp[i-1]计算出,每项都乘m-1,表示从这个长度往后都是一种与它最后一个格不同的颜色,则 d p [ i ] = ( m − 1 ) ∑ j = i − k + 1 i − 1 d p [ j ] dp[i]=(m-1)\sum_{j=i-k+1}^{i-1}dp[j] dp[i]=(m1)j=ik+1i1dp[j],可以用前缀和优化做出。题解中的技巧:用s[i]表示前i项和, s [ i ] − s [ i − 1 ] = ( m − 1 ) ( d p [ i − 1 ] − d p [ i − k ] ) s[i]-s[i-1]=(m-1)(dp[i-1]-dp[i-k]) s[i]s[i1]=(m1)(dp[i1]dp[ik]),整理得 s [ i ] = m ∗ s [ i − 1 ] − ( m − 1 ) ∗ s [ i − k ] s[i]=m*s[i-1]-(m-1)*s[i-k] s[i]=ms[i1](m1)s[ik]然后计算s数组,避免前缀和优化。

A:

#include<cstdio>
#include<string>
#include<cstring>
#include<utility>
#include<cmath>
#include<map>
#include<queue>
#include<set>
#include<algorithm>
#include<vector>
#include<iostream>
#define ll long long
#define pii pair<int,int>
#define mp make_pair
#define fi first
#define se second
#define inf 0x7fffffff
#define minn(x,y) x=min(x,y)
#define maxx(x,y) x=max(x,y)
using namespace std;
pair<int,pii> a[100010];
pair<pii,int> r[100010];
int fa[100010],c[100010];
int find(int x)
{
	if(fa[x]==x)
	{
		return x;
	}
	return fa[x]=find(fa[x]);
}
int add(pair<int,pii> x)
{
	int fx=find(x.se.fi);
	int y=find(x.se.se);
	c[fx]+=c[y];
	fa[y]=fx;
}
int ans[100010];
int main()
{
	int i,j,k,n,m,x,y,z,q;
	freopen("mootube.in","r",stdin);
	freopen("mootube.out","w",stdout);
	scanf("%d%d",&n,&q);
	for(i=0;i<n-1;i++)
	{
		scanf("%d%d%d",&x,&y,&z);
		a[i]=mp(z,mp(x,y));
	}
	sort(a,a+n-1);
	reverse(a,a+n-1);
	for(i=0;i<q;i++)
	{
		scanf("%d%d",&x,&y);
		r[i]=mp(mp(x,y),i);
	}
	sort(r,r+q);
	reverse(r,r+q);
	j=0;
	for(i=0;i<=n;i++)
	{
		fa[i]=i;
		c[i]=1;
	}
	for(i=0;i<q;i++)
	{
		while(a[j].fi>=r[i].first.fi)
		{
			add(a[j]);
			j++;
		}
		ans[r[i].se]=c[find(r[i].first.se)]-1;
	}
	for(i=0;i<q;i++)
	{
		printf("%d\n",ans[i]);
	}
}

B:

#include<cstdio>
#include<string>
#include<cstring>
#include<utility>
#include<cmath>
#include<map>
#include<queue>
#include<set>
#include<algorithm>
#include<vector>
#include<iostream>
#define ll long long
#define pii pair<int,int>
#define mp make_pair
#define fi first
#define se second
#define inf 0x7fffffff
#define minn(x,y) x=min(x,y)
#define maxx(x,y) x=max(x,y)
using namespace std;
vector<int> ve[100010];
int d[100010],d1[100010];
int dfs1(int x,int q,int p)
{
	d[x]=q;
	int i,l=0x7ffffff;
	for(i=0;i<ve[x].size();i++)
	{
		if(ve[x][i]!=p)
		{
			l=min(l,dfs1(ve[x][i],q+1,x));
		}
	}
	if(l==0x7ffffff)
	{
		d1[x]=0;
	//	printf("%d %d %d\n",x,q,0);
		return 0;
	}
	d1[x]=l+1;
//	printf("%d %d %d\n",x,q,l+1);
	return l+1;
}
int dfs(int x,int p)
{
	if(d1[x]<=d[x])
	{
		return 1;
	}
	int ans=0;
	for(int i=0;i<ve[x].size();i++)
	{
		if(ve[x][i]!=p)
			ans+=dfs(ve[x][i],x);
	}
	return ans;
}
int main()
{
	int i,j,k,n,m,x,y,z;
	freopen("atlarge.in","r",stdin);
	freopen("atlarge.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(i=1;i<n;i++)
	{
		scanf("%d%d",&x,&y);
		ve[x].push_back(y);
		ve[y].push_back(x);
	}
	dfs1(m,0,-1);
	cout<<dfs(m,-1);
}

C:

#include<cstdio>
#include<string>
#include<cstring>
#include<utility>
#include<cmath>
#include<map>
#include<queue>
#include<set>
#include<algorithm>
#include<vector>
#include<iostream>
#define ll long long
#define pii pair<int,int>
#define mp make_pair
#define fi first
#define se second
#define inf 0x7fffffff
#define minn(x,y) x=min(x,y)
#define maxx(x,y) x=max(x,y)
using namespace std;
ll mod=1e9+7;
int s[1000010];
int main()
{
	int i,j,k,n,m,x,y,z;
	freopen("spainting.in","r",stdin);
	freopen("spainting.out","w",stdout);
	scanf("%d%d%d",&n,&m,&k);
	for(i=1;i<k;i++)
	{
		s[i]=(1ll*s[i-1]*m%mod+m)%mod;
	}
	for(i=k;i<=n;i++)
	{
		s[i]=(1ll*m*s[i-1]%mod-1ll*(m-1)*s[i-k]%mod+mod)%mod;
	}
	int sum=1;
	for(i=0;i<n;i++)
	{
		sum=1ll*sum*m%mod;
	}
	printf("%d",(1ll*sum+mod-(s[n]-s[n-1])%mod)%mod);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值