[BZOJ]容易题 [HAOI2012]
题目描述
为了使得大家高兴,小Q特意出个自认为的简单题(easy)来满足大家,这道简单题是描述如下:
有一个数列A已知对于所有的A[i]都是1~n的自然数,并且知道对于一些A[i]不能取哪些值,我们定义一个数列的积为该数列所有元素的乘积,要求你求出所有可能的数列的积的和 mod 1000000007的值,是不是很简单呢?呵呵!
输入输出格式
输入格式:
第一行三个整数n,m,k分别表示数列元素的取值范围,数列元素个数,以及已知的限制条数。
接下来k行,每行两个正整数x,y表示A[x]的值不能是y。
输出格式:
一行一个整数表示所有可能的数列的积的和对1000000007取模后的结果。如果一个合法的数列都没有,答案输出0。
输入输出样例
输入样例
3 4 5
1 1
1 1
2 2
2 3
4 3
输出样例
90
说明
样例解释
A[1]不能取1
A[2]不能去2、3
A[4]不能取3
所以可能的数列有以下12种
数列 | 积 |
---|---|
2 1 1 1 | 2 |
2 1 1 2 | 4 |
2 1 1 4 | 4 |
2 1 2 2 | 8 |
2 1 3 1 | 6 |
2 1 3 2 | 12 |
3 1 1 1 | 3 |
3 1 1 2 | 6 |
3 1 2 1 | 6 |
3 1 2 2 | 12 |
3 1 3 1 | 9 |
3 1 3 2 | 18 |
30%的数据$$n \leq 4,m\leq 10,k \leq 10$$
另有20%的数据$$k=0$$
70%的数据$n \leq 1000,m \leq 1000,k \leq 1000$
100%的数据 $n \leq 10^9,m \leq 10^9,k \leq 10^5,1 \leq y \leq n,1 \leq x \leq m$
思路
数论
分类讨论:
对于$$k=0$$:
$$ans= (\sum _{i=1} ^n i)^m$$
对于$$k \neq 1$$
$$ans=P \times Q$$
其中:
$$P=(\sum _{i=1} ^n i)-y(被限制的数字)$$
$$Q=(\sum _{i=1} ^n i)^{m-cnt};(cnt为被限制的位数)$$
注意:需要去重;负数取模
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
const int mod = 1e9 + 7;
ll n, k, m;
struct node { ll x; ll y; };
node a[maxn];
ll sum = 0;
ll sig[maxn];
ll ans = 0;
int cmp(node x, node y)
{
return (x.x == y.x) ? (x.y < y.y) : (x.x < y.x);
}
ll powmod(ll a, ll b)
{
ll ret = 1;
while (b)
{
if (b & 1) ret = ret*a %mod;
a = a*a%mod;
b >>= 1;
}
return ret;
}
int main()
{
scanf("%lld %lld %lld", &n, &m, &k);
sum = (1 + n)*n / 2 % mod;
for (int i = 1; i <= k; i++)
{
scanf("%lld %lld", &a[i].x, &a[i].y);
}
sort(a + 1, a + k + 1, cmp);
ll cnt = 0;
for (int i = 1; i <= k; i++)
{//去重
if (a[i].x != a[i - 1].x)
sig[++cnt] = sum;
else
{
if (a[i].y == a[i - 1].y) continue;
}
sig[cnt] = (sig[cnt] - a[i].y + mod) % mod;
}
ans += powmod(sum, m - cnt);
for (int i = 1; i <= cnt; i++)
{
ans = (ans*sig[i] + mod) % mod;
}
printf("%lld\n", ans);
}