HDOJ 5498 Tree

容斥一下然后生成树计数就行了....

#include 
using namespace std;
typedef long long LL;

const int maxn = 105;

int a[maxn][maxn];
LL c[maxn][maxn];
int base, n, m, q;

int det(int n)
{
    int ans = 1, i, j, k;
    bool flag = true;
    for (i = 1; i < n; i++)
        for (j = 1; j < n; j++) a[i][j] = (a[i][j] + base) % base;
    for (i = 1; i < n; i++)
    {
        for (j = i + 1; j < n; j++)
            while (a[j][i])
            {
                int t = a[i][i] / a[j][i];
                for (k = i; k < n; k++) a[i][k] = (a[i][k] + base - (LL)t * (LL)a[j][k] % base) % base;
                for (k = i; k < n; k++) swap(a[i][k], a[j][k]);
                flag ^= true;
            }
        ans = (LL)ans * (LL)a[i][i] % base;
        if (!ans) return 0;
    }
    if (!flag) ans = (base - ans);
    return ans;
}

void init()
{
	int N = 100;
	c[0][0] = 1 % base;
	for(int i = 1; i <= N; i++) {
		c[i][0] = 1 % base;
		for(int j = 1; j <= i; j++)
			c[i][j] = (c[i-1][j] + c[i-1][j-1]) % base;
	}
}

LL powmod(LL a, LL b)
{
	LL res = 1, BASE = a;
	while(b) {
		if(b % 2) res = res * BASE % base;
		BASE = BASE * BASE % base;
		b /= 2;
	}
	return res;
}

void work()
{
	scanf("%d%d%d%d", &n, &m, &base, &q);
	init();
	
	memset(a, 0, sizeof a);
	for(int i = 1; i <= m; i++) {
		int u, v;
		scanf("%d%d", &u, &v);
		a[u][v]--, a[v][u]--;
		a[u][u]++, a[v][v]++;
	}
	
	int res = det(n);
	LL cnt = powmod(n-1, q);
	for(int i = 1; i <= n-1; i++) {
		if(i & 1) cnt = (cnt - c[n-1][i] * powmod(n-1-i, q) % base) % base;
		else cnt = (cnt + c[n-1][i] * powmod(n-1-i, q) % base) % base;
	}
	
	LL ans = cnt * res % base;
	ans = (ans % base + base) % base;
	printf("%lld\n", ans);
}

int main()
{
//freopen("data", "r", stdin);
	int _;
	scanf("%d", &_);
	while(_--) work();
	
	return 0;
}


你可能感兴趣的:(HDOJ 5498 Tree)