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\) 取模的结果。
解决办法
首先对于没有任何限制的情况讨论
其中一个二元限制,显然有
接着对于一段下标为1-4的限制进行讨论
其中\(X\) \(Y\)表示两个一元限制 \(c_1=X\) \(c_4=Y\)

在这种情况下不可能满足要求的情况有
即当且仅当\(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;
}

浙公网安备 33010602011771号