【xdoj难题集】1116 Dominator Orz Pandas

不知道为什么做的人很少,其实是一道思维题,想通了很简单,另外吐槽一下这道题坑人的m,竟然里面的重要城市可能会重复,这不是存心害人吗?我就不知道谁平常说话说有m个重要城市还能有重复的,当时没看见搞了我20分钟检查,真的坑。

并没有什么技术性难题,完全是思想,考虑一个重要城市,假如子树大小为k,那么会发现其实有这个城市相比于没有这个城市只是让答案除k了,为什么呢?因为如果没有这个城市,不管这个城市选什么值我们都会在后面的城市得到一系列的排列,而这些值都是等价的,所以这个城市选哪个值并不影响后面有多少个结果,那么如果有了这个城市,那么只有最大值在这个城市的时候才是对的,所以相比于没有限制,当然是结果除k了,所以初始情况n!种,再除以所有重要城市子树数量之积即可。数量的逆元和阶乘的模都可以o(n)打表得到(要有些技巧)。

贴代码

# include <stdio.h>
# include <string.h>
# include <vector>

using namespace std;

typedef long long ll;

const int MAX_N = 1e5 + 5;
const int Mod = 1e9 + 7; 

bool used[MAX_N];

vector<int> G[MAX_N];
int d[MAX_N];

ll jie[MAX_N + 1], ni[MAX_N + 1]; 
int N, M;

int dfs(int prv , int x)
{
	int ans = 1, i;
	for(i = 0 ; i < G[x].size() ; i++)
	{
		int t = G[x][i];
		if(t == prv)
			continue;
			
		ans += dfs(x , t);
	}
	
	return d[x] = ans;
}

void solve()
{
	dfs(-1 , 0);
	ll ans = jie[N];
	//printf("haha%d\n", d[0]);
	memset(used , 0 , sizeof(used));
	
	int i, c;
	for(i = 0 ; i < M ; i++)
	{
		scanf("%d", &c);
		c--;
		if(!used[c])
		{
			used[c] = 1;
			ans = ans * ni[d[c]] % Mod;
		}
	}
	
	printf("%lld\n", ans);
}

int main()
{
	jie[0] = jie[1] = 1;
	ni[0] = ni[1] = 1;
	
	int i;
	for(i = 2 ; i <= MAX_N ; i++)
		jie[i] = jie[i - 1] * i % Mod;
		
	for(i = 2 ; i <= MAX_N ; i++)
		ni[i] = ni[Mod % i] * (Mod - Mod / i) % Mod;
	
	//printf("%lld\n", 19261 * ni[19261] % Mod);
	
	while(~scanf("%d %d", &N, &M))
	{
		int i, t, s;
		for(i = 0 ; i < N - 1 ; i++)
		{
			scanf("%d %d", &t, &s);
			t--;
			s--;
			G[t].push_back(s);
			G[s].push_back(t);
		}
		
		solve();
		
		for(i = 0 ; i < N ; i++)
			G[i].clear();
	}
	
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/qq_40772738/article/details/79972584