[bzoj2751][HAOI2012]容易题(easy)

Description

给出一个m个数的序列,每个数可以是1~n中的任意一个数。再给出k个限制,每个限制形为x,y,表示第x个数不能是y。求所有可能的序列积的和。
序列积定义为序列中所有数的积。
n,m<=10^9,k<=10^5

Solution

很显然的,easy题就是easy。
若没有限制,那么答案就是 (n(n+1)2)m
有限制的话,求出每个有限制位置的数可以的和,然后乘起来,最后的部分用快速幂搞掂就好了。

Code

#include<map>
#include<cstdio>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define N 100005
using namespace std;
typedef long long ll;
const int mo=1000000000+7;
map<int,int> h,pd[N];
ll ans,sum,a[N];
int n,m,k,x,y,tot;
ll mi(ll x,int y) {
    ll z=x;
    for(y--;y;y/=2) {
        if (y&1) (z*=x)%=mo;
        (x*=x)%=mo;
    }
    return z;
}
int main() {
    scanf("%d%d%d",&n,&m,&k);
    sum=(ll)n*(n+1)/2%mo;
    fo(i,1,k) {
        scanf("%d%d",&x,&y);
        if (!h[x]) h[x]=++tot;x=h[x];
        if (pd[x][y]) continue;
        (a[x]+=(ll)mo-y)%=mo;pd[x][y]=1;
    }ans=mi(sum,m-tot);
    fo(i,1,tot) (ans*=a[i]+sum)%=mo;
    printf("%lld",ans);
}

Ps:离散化开了map作弊,有没有什么更好的办法?求带

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值