NOIP2024 遗失的赋值

题目描述

小 F 有 \(n\) 个变量 \(x_1,x_2, ... ,x_n\)。每个变量可以取 \(1\)\(v\) 的整数取值。

小 F 在这 \(n\) 个变量之间添加了 \(n-1\) 条二元限制,其中第 \(i(1 \leq i \leq n-1)\) 条限制为:若 \(x_i = a_i\),则要求 \(x_{i + 1} = b_i\)\(a_i\)\(b_i\)\(1\)\(v\) 之间的整数。当 \(x_i \neq a_i\) 时,第 \(i\) 条限制对 \(x_{i + 1}\) 的值不做任何约束。除此之外,小 F 还添加了 \(m\) 条一元限制,其中第 \(j(1 \leq j \leq m)\) 条限制为:\(x_{c_j} = d_j\)

小 F 记住了所有 \(c_j\)\(d_j\) 的值,但把所有 \(a_i\)\(b_i\) 的值都忘了。同时小 F 知道:存在给每一个变量赋值的方案同时满足所有这些限制。

现在小 F 想知道,有多少种 \(a_i,b_i(1 \leq i \leq n - 1)\) 取值的组合,使得能够确保至少存在一种给每个变量 \(x_i\) 赋值的方案可以同时满足所有限制。由于方案数可能很大,小 F 只需要你输出方案数对 \(10^9 + 7\) 取模的结果。

解决办法

首先对于没有任何限制的情况讨论

其中一个二元限制,显然有

\[\large\begin{cases} a_i \quad \text可选择的数值有 \quad v\\ b_i \quad \text可选择的数值有 \quad v \end{cases} \text 一共 $v^2$ 种选法 \]

接着对于一段下标为1-4的限制进行讨论
其中\(X\) \(Y\)表示两个一元限制 \(c_1=X\) \(c_4=Y\)

在这种情况下不可能满足要求的情况有

\[\Large\begin{cases} a_1 \quad 1\\ b_1 \quad v \end{cases} \quad \begin{cases} a_2 \quad 1\\ b_2 \quad v \end{cases} \quad \begin{cases} a_3 \quad 1\\ b_3 \quad v - 1 \end{cases} \text一共2v\times(v-1)种选法 \]

即当且仅当\(a_1=X,b_1=a_2,b_2=a_3,b_3\ne Y\)时没有满足条件的选法

于是我们对一组数据分为几部分

\(\large\Box X\Box\Box\Box\Box\Box XX\Box\Box X\Box\Box\)这样一段为例
分为
\(\large\Box X\)
\(\large X\Box\Box\Box\Box\Box X\)
\(\large XX\)
\(\large X\Box\Box X\)
\(\large X\Box\Box\)
五段分别计算

最后,数据范围 \(n \leq 1e9,m \leq 1e5\) 鉴定为对 \(1~m\) 中每个一元限制遍历处理

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int M = 100005;
const int mod = 1e9 + 7;

int rd()//快读

int T;
int n,m,v;
int Pow(int a,int b)
{
    int ans = 1,base = a;
    while(b)
    {
        if(b & 1)
        {
            ans *= base;
            ans %= mod;
        }
        base *= base;
        base %= mod;
        b >>= 1;
    }
    return ans % mod;
}
struct node
{
    int c,d;
    bool operator < (const node &a) const
    {
        return c < a.c;
    }
}a[M];
int vis[M];

signed main()
{
    T = rd();
    while(T--)
    {
        int cnt = 0;
        int ans = 1;
        n = rd(),m = rd(),v = rd();
        int x = ((v * v) + mod) % mod;
        for(int i = 1;i <= m;i++) a_i.c = rd(),a_i.d = rd();
        sort(a + 1,a + m + 1);
        bool flag = 0;
        a[0].c = 0;
        for(int i = 1;i <= m;i++)
        {
            if(a_i.c == a[i - 1].c)
            {
                if(a_i.d != a[i - 1].d)
                {
                    cout << "0\n";
                    flag = 1;
                    break;
                }
            }
            else vis[++cnt] = a_i.c;
        }
        if(flag) continue;
        for(int i = 2;i <= cnt;i++)
        {
            ans *= (Pow(x,vis_i - vis[i - 1]) - (Pow(v,vis_i - vis[i - 1] - 1) * (v - 1) + mod) % mod + mod) % mod;
            ans %= mod;
        }
        if(vis[1] - 1)
        {
            ans *= (Pow(x,vis[1] - 1) + mod) % mod;
            ans %= mod;
        }
        if(n - vis[cnt])
        {
            ans *= (Pow(x,n - vis[cnt]) + mod) % mod;
            ans %= mod;
        }
        cout << ans << '\n';
    }
    return 0;
}
posted @ 2024-12-05 20:49  IC0CI  阅读(159)  评论(0)    收藏  举报