hdu-6986 dfs,加减1法统计种类数

hdu-6986
VJ链接
题意:
给定一棵树,每棵树有一个点权 c i ∈ [ 1 , n ] c_i\in[1,n] ci[1,n]
定义 p ( u , v ) p(u,v) p(u,v) 表示 u u u–> v v v 这条路径上点权的种类数
a i j a_{ij} aij 表示 p ( i , j ) p(i,j) p(i,j) 这条路径上的种类数
定义
f ( i , x ) = ∑ j = 1 n a i , j x j − 1 f(i,x)=\sum_{j=1}^n a_{i,j}x^{j-1} f(i,x)=j=1nai,jxj1
每个测试点输出 n n n 行,每行输出两个数, f ( i , 19560929 ) % ( 1 0 9 + 7 ) f(i,19560929)\% (10^9+7) f(i,19560929)%(109+7) f ( i , 19560929 ) % ( 1 0 9 + 9 ) f(i,19560929) \% (10^9+9) f(i,19560929)%(109+9)
思路:
加减一法
在这里插入图片描述
code:

#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define ld long double
#define all(x) x.begin(), x.end()
#define mem(x, d) memset(x, d, sizeof(x))
#define eps 1e-6
using namespace std;
const int maxn = 2e3 + 9;
const int mod1 = 1e9 + 7;
const int mod2 = 1e9 + 9;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll n, m;
const int b  = 19560929;
int base1[maxn], base2[maxn], c[maxn], p[maxn], cnt[maxn];
vector <int> e[maxn];
int ans;
void init(){
	base1[0] = base2[0] = 1;
	for(int i = 1; i <= maxn - 9; ++i){
		base1[i] = 1ll * base1[i-1] * b % mod1;
		base2[i] = 1ll * base2[i-1] * b % mod2;
	}
}
inline void add(int x)
{
	if (!cnt[x]) ++ans;
	++cnt[x];
}
inline void del(int x)
{
	if (cnt[x] == 1) --ans;
	--cnt[x];
}
void dfs(int x, int fa){
	add(c[x]);
	p[x] = ans;
	for(auto to : e[x]) if(to != fa) dfs(to, x);
	del(c[x]);
}
void work()
{
	cin >> n;
	for(int i = 1; i <= n; ++i) e[i].clear();
	ans = 0;
	for(int i = 1; i < n; ++i){
		int x, y;cin >> x >> y;
		e[x].push_back(y);
		e[y].push_back(x);
	}
	for(int i = 1; i <= n; ++i) cin >> c[i];
	for(int i = 1; i <= n; ++i){
		dfs(i, -1);
		ll ans1 = 0, ans2 = 0;
		for(int j = 1; j <= n; ++j)
		{
			(ans1 += 1ll * base1[j-1] * p[j]) %= mod1;
			(ans2 += 1ll * base2[j-1] * p[j]) %= mod2;
		}
		cout << ans1 << " " << ans2 << endl;
	}
}

int main()
{
	ios::sync_with_stdio(0);
	init();
//	int TT;cin>>TT;while(TT--)
	work();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值