"蔚来杯"2022牛客暑期多校训练营4-D-Jobs (Easy Version)
原题链接:https://ac.nowcoder.com/acm/contest/33189/D
题目大意
有
n
n
n个公司,每个公司有
m
i
m_i
mi个工作,每个工作对一个人的"三商"——IQ,EQ,AQ有最低限度。现在有
q
q
q个人来应聘,他们的"三商"由给定种子(seed)所产生的随机数决定。当一个人的"三商"全部大于等于一个工作所对应的"三商"后,他就会收到该公司的offer(即使他满足一个公司的多个工作需求,也只会受到
1
1
1个offer)。现在求答案:(
p
i
p_i
pi为第i个人能收到的offer数)
(
∑
i
=
1
q
p
i
.
s
e
e
d
q
−
i
)
m
o
d
998244353
(\sum_{i=1}^{q}p_i.seed^{q-i}) mod 998244353
(∑i=1qpi.seedq−i)mod998244353
解析
由于"三商"的范围在 1 − 400 1-400 1−400之间,我们可以用一个三维数组 m a p p i , j , k mapp_{i,j,k} mappi,j,k来表示当一个人 I Q , E Q , A Q IQ,EQ,AQ IQ,EQ,AQ分别为 i , j , k i,j,k i,j,k时能收到offer的状态。由于一个公司可能有多个工作,差分不能直接统计offer的数量,但 n n n最大为 10 10 10,因此我们可以用二进制数来保存这个状态,若第 i − 1 i - 1 i−1位为1,就说明他会收到 i i i公司的offer。然后从三个不同维度分别差分,后一位要 ∣ = |= ∣=(位或)前一位,这样同一个公司的offer数就不会被多次计算,offer总数也能统计。这样对于每一对 I Q , E Q , A Q IQ,EQ,AQ IQ,EQ,AQ,只需要 O ( 1 ) O(1) O(1)的时间复杂度,预处理也只需 O ( n 3 ) O(n^3) O(n3)的复杂度,还是可以通过的。 s e e d q − i seed^{q-i} seedq−i使用快速幂计算即可。
代码展现
#include<iostream>
#include<cstdio>
#include<random>
using namespace std;
typedef long long ll;
const ll mod = 998244353;
int n,q,seed,mapp[410][410][410];
ll ksm(ll x,ll p){
ll res = 1;
while(p){
if(p % 2){
res = res * x % mod;
}
x = x * x % mod;
p /= 2;
}
return res;
}
int solve(int IQ,int EQ,int AQ){
return mapp[IQ][EQ][AQ];
}
int main(){
ll ans = 0;
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++){
int t;
scanf("%d",&t);
for(int j=1;j<=t;j++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
mapp[a][b][c] |= (1 << (i - 1));
// 将第i - 1位设为1
}
}
// 三维差分
for(int i=1;i<=405;i++){
for(int j=1;j<=405;j++){
for(int k=2;k<=405;k++){
mapp[i][j][k] |= mapp[i][j][k - 1];
}
}
}
for(int i=1;i<=405;i++){
for(int j=1;j<=405;j++){
for(int k=2;k<=405;k++){
mapp[i][k][j] |= mapp[i][k - 1][j];
}
}
}
for(int i=1;i<=405;i++){
for(int j=1;j<=405;j++){
for(int k=2;k<=405;k++){
mapp[k][j][i] |= mapp[k - 1][j][i];
}
}
}
for(int i=1;i<=405;i++){
for(int j=1;j<=405;j++){
for(int k=1;k<=405;k++){
int num = 0;
while(mapp[i][j][k]){
if(mapp[i][j][k] % 2){
num++;
}
mapp[i][j][k] /= 2;
}
mapp[i][j][k] = num;
}
}
}
scanf("%d",&seed);
std::mt19937 rng(seed);
std::uniform_int_distribution<> u(1,400);
int lastans=0;
for (int i=1;i<=q;i++)
{
int IQ=(u(rng)^lastans)%400+1; // The IQ of the i-th friend
int EQ=(u(rng)^lastans)%400+1; // The EQ of the i-th friend
int AQ=(u(rng)^lastans)%400+1; // The AQ of the i-th friend
lastans=solve(IQ,EQ,AQ); // The answer to the i-th friend
ans = (ans + (ll)lastans * ksm(seed,q - i) % mod ) % mod;
}
printf("%lld\n",ans);
}