洛谷 2220 [HAOI2012]容易题 题解(组合数学,离散化)

版权声明:博主是个蒟蒻,希望大家支持,如果要转发就转发吧,把我链接挂上即可。 https://blog.csdn.net/LightningUZ/article/details/90143389

原链接:
洛谷:点我QωQ
bzoj:点我QωQ

题意简述

一个长度为 m m 的数列 a a ,每个数都在 [ 1 , n ] [1,n] 之间,有 k k 个限制。第 i i 个限制包含两个正整数 x , y x,y ,表示 a x a_x 不能取 y y 。求所有满足条件的 a a 数列的所有元素之积之和。

数据

输入

第一行三个正整数, n , m , k n,m,k ( n , m < = 1 0 9 , k < = 1 0 5 ) (n,m<=10^9,k<=10^5)
接下来 k k 行,每行两个正整数 x , y x,y 1 < = x < = m , 1 < = y < = n 1<=x<=m,1<=y<=n

输出

所有满足条件的 a a 数列的所有元素之积之和。

样例

输入
3 4 5
1 1
1 1
2 2
2 3
4 3
输出
90

解释

有一下几种:

数列
2 1 1 1 2
2 1 1 2 4
2 1 2 1 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

很明显,表中"积"一项的和为 2 + 4 + 4 + 8 + 6 + 12 + 3 + 6 + 6 + 12 + 9 + 18 = 90 2+4+4+8+6+12+3+6+6+12+9+18=90

思路

题目名称叫"容易题",但是我非常想叫它"毒瘤题",我艹太 t m ^{tm} 毒瘤了。。。

虽然样例解释给出的是暴力形式,但是显然我们是不珂以暴力做的。
我们想想(拿 n = 4 , m = 4 n=4,m=4 举例),如果没有任何限制,那么积的和是多少呢?

显然,每个位置都珂以取 1 , 2 n 1,2\cdots n ,合法的数列有
{ 1 , 2 , 3 , 1 } \{1,2,3,1\} , { 1 , 2 , 3 , 2 } \{1,2,3,2\} , { 1 , 2 , 3 , 3 } \{1,2,3,3\} , { 1 , 2 , 3 , 4 } \{1,2,3,4\} , \cdots
这是前四项。如果我们计算它们积的和,我们会发现珂以提一个公因式 1 × 2 × 3 1\times 2\times 3 出来,然后最后一项是 ( 1 + 2 + 3 + 4 ) (1+2+3+4) ,即这四个数列积的和为 ( 1 × 2 × 3 ) × ( 1 + 2 + 3 + 4 ) (1\times 2\times 3)\times (1+2+3+4) .当然,我们珂以想象一下,如果我们把所有项都因式分解,应该长这样:
= ( 1 + 2 + 3 + 4 ) × ( 1 + 2 + 3 + 4 ) × ( 1 + 2 + 3 + 4 ) × ( 1 + 2 + 3 + 4 ) = ( 1 + 2 + 3 + 4 ) m = ( n ( n + 1 ) 2 ) m =(1+2+3+4)\times (1+2+3+4)\times (1+2+3+4) \times(1+2+3+4)=(1+2+3+4)^m=(\frac{n(n+1)}{2})^m

此时,我们考虑限制,按样例,第一个不能取 1 1 。此时我们发现,分解完的结果长成这样:
( 2 + 3 + 4 ) × ( 1 + 2 + 3 + 4 ) 3 (2+3+4)\times(1+2+3+4)^3
就是第一个括号里少加了一个 1 1 。也就是说,对于一个限制 ( x , y ) (x,y) ,即第 x x 个位置不能取 y y ,对答案的影响就是第 x x 个括号里减去一个 y y 。(从样例中发现,有些限制会重复出现,这很好办,排序一下,然后 w h i l e while 循环替代 + + i ++i 即可)我们用 c n t [ i ] cnt[i] 表示第 i i 个括号里的值,每次减一下,到最后乘起来就是答案了。

扫描二维码关注公众号,回复: 6216069 查看本文章

当你开开心心的写完这个代码的时候,你会发现: w d n m d , m < = 1 0 9 wdnmd,m<=10^9 !!! F K F**K
所以我们需要优化。发现 k k 并不大,只有 1 0 5 10^5 ,所以只有这 k k 个做过改动的对答案有影响,其它的就直接快速幂上去即可。由于我们刚刚在去重的时候就已经排过序了,所以代码也就没有什么变动,具体看注释。代码:

#include<bits/stdc++.h>
using namespace std;
namespace Flandle_Scarlet
{
    #define int long long
    #define mod 1000000007
    #define K 100100
    int n,m,k;
    struct node//保存一个约束
    {
        int pos,val;
        //位置,不能等于的值
    }a[K];bool operator<(node x,node y){return x.pos<y.pos or (x.pos==y.pos and x.val<y.val);}
    //排序:位置第一优先,不能等于的值第二优先
    void Input()
    {
        scanf("%lld%lld%lld",&n,&m,&k);
        for(int i=1;i<=k;++i)
        {
            scanf("%lld%lld",&a[i].pos,&a[i].val);
        }
        sort(a+1,a+k+1);//记得排序
    }

    int cnt[K];//每个括号里的值
    //这里只记录被改动过的括号,别的括号里的值用快速幂乘上去
    int qpow(int a,int b,int m)//快速幂
    {
        int r=1;
        while(b)
        {
            if (b&1) r=r*a%m;
            a=a*a%m,b>>=1;
        }
        return r;
    }
    int Next(int pos)//去重用的,用一个while循环找到第一个不相同的约束条件
    //样例里就有一个相同的...真tm毒瘤..
    {
        ++pos;
        if (a[pos].pos!=a[pos-1].pos) return pos;
        while(a[pos].val==a[pos-1].val) ++pos;
        return pos;
    }
    void Solve()
    {
        int sum=n*(n+1)/2;sum%=mod;//没有被改动过的括号的值
        for(int i=1;i<=k;++i)
        {
            cnt[i]=sum;
        }//初始都是=sum的

        int pos=0;//由于有一些不同的约束条件描述的是一个相同的位置(不能等于的值不同),
        //所以剩下的括号并不是n-k个,而是用这个pos存一下不同的个数
        for(int i=1;i<=k;i=Next(i))
        {
            if (a[i].pos!=a[i-1].pos)
            {
                ++pos;//如果描述的位置不同,就++
            }
            cnt[pos]=(cnt[pos]-a[i].val+mod)%mod;//对答案产生影响,所以要修改括号中的值
            //不能直接模,要+mod再模
        }
        int rest=m-pos;//剩下m-pos个括号里都是sum
        int ans=qpow(sum,rest,mod);//用快速幂乘上去
        for(int i=1;i<=pos;++i)
        {
            ans*=cnt[i];ans%=mod;
        }//这一步上面解释过了
        printf("%lld\n",ans);
    }
    void Main()
    {
        if (0)
        {
            freopen("","r",stdin);
            freopen("","w",stdout);
        }
        Input();
        Solve();
    }
    #undef int //long long
    #undef mod //1000000007
};
main()
{
    Flandle_Scarlet::Main();
    return 0;
}

回到总题解界面

猜你喜欢

转载自blog.csdn.net/LightningUZ/article/details/90143389
今日推荐