[三维前缀或]Jobs (Easy Version) 2022牛客多校第4场 D

题目描述

See Problem N for PDF statements.

Note: The only difference between the easy and the hard version is the constraints on nnn and mim_imi​.


Since Little Horse gets a golden prize in a programming contest, many companies send offers to him. There are nnn companies, and the iii-th company has mim_imi​ available jobs. To get an offer from a company, you need to be qualified for the job.

How to be qualified? The company will test your "three quotients": IQ (Intelligence Quotient), EQ (Emotional Quotient), and AQ (Adversity Quotient). Each job has three lower limits of the three quotients respectively. If all of your IQ, EQ, and AQ are no less than the corresponding lower limits, you are qualified for the job. As long as you are qualified for at least one job in a company, the company will send an offer to you.
 

Little Horse's three quotients are all high enough, so all the companies send offers to him. But Little Horse has qqq friends that worry about their jobs. Given the value of IQ, EQ and AQ of each friend, Little Horse wants to know how many companies will send offers to each friend.

In this problem, the IQEQ, and AQ of these qqq friends are generated as below.

First, register an mt19937\texttt{mt19937}mt19937 random engine rng\texttt{rng}rng with the seed\texttt{seed}seed and a uniform integer distribution object.

#include <random>
std::mt19937 rng(seed);
std::uniform_int_distribution<> u(1,400);

Then, the value of IQ, EQ, and AQ are generated as follows.

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
}

输入描述:

The first line of input contains two integers n,qn,qn,q (1≤n≤101 \le n \le 101≤n≤10, 1≤q≤2×1061 \le q \le 2\times 10^61≤q≤2×106), indicating the number of companies and Little Horse's friends.

Then in the next nnn lines, the first integer of the iii-th line is mim_imi​ (1≤mi≤1051 \le m_i \le 10^51≤mi​≤105) --- the number of jobs in the iii-th company. Then there follow 3mi3m_i3mi​ integers. The jjj-th triple integers aj,bj,cja_j,b_j,c_jaj​,bj​,cj​ (1≤aj,bj,cj≤4001 \le a_j,b_j,c_j \le 4001≤aj​,bj​,cj​≤400) indicate the lower limits of IQ, EQ, and AQ for the jjj-th job in the iii-th company.

The next line contains one integer seed\text{seed}seed (108≤seed<23110^8\le \text{seed}<2^{31}108≤seed<231). Then the IQ ,EQ, and AQ of these qqq friends are generated as above.

输出描述:

Let's denote the answer to the iii-th friend as ansi\text{ans}_iansi​. You should output:

(∑i=1qansi⋅seedq−i) mod 998244353\left( \sum_{i=1}^q\text{ans}_i\cdot\text{seed}^{q-i} \right) \bmod 998244353(∑i=1q​ansi​⋅seedq−i)mod998244353

in a single line.

示例1

输入

3 5
2 1 1 2 2 1 2
3 1 3 2 2 3 1 2 3 3
2 2 3 1 3 2 1
191415411

输出

34417749

题意: 给出n个公司,每个公司都有若干职位,再给出m个人的三属性以及每个公司每个职位的三属性要求,当某人三属性均不小于要求时就可以胜任该职位,一个人最多只能胜任同一个公司的一个职位,但可以同时胜任多个公司的职位,问这m个人胜任的职位数加和是多少。

分析: 一开始想到的是三维差分+前缀和,对于每个公司分别维护(i, j, k)能胜任的职位数,但是这道题由于强制在线,所以必须算完第i个人对于n个公司的职位数才能开始计算第i+1个人的职位数,这就导致差分数组必须多开一维分别存储不同公司的职位信息,但是这样会超空间,所以必须要换思路了。

实际上由于公司数很少,最多也才10个公司,那么可以用二进制位来标识某一公司,同时由于我们只关注(i, j, k)能否胜任,并不关注在一个公司内它能胜任几个职位,所以可以用前缀或来维护,这样大体思路也就明确了,用三维前缀或中的第i位来维护第i个公司的职位信息,由于位或运算时各位是相互独立的,所以公司和公司之间不会相互影响,最终只需要统计每个人三属性对应的前缀或值中1的个数,这就是他能胜任的职位数。

具体代码如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
#include <random>
using namespace std;

int seed;
const int N=401, mod = 998244353;
int f[N][N][N];
int s[2000005];//s[i] = (seed^i)%mod
int lastans=0;
std::uniform_int_distribution<> u(1,400);

inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

int main(){
	int n, m;
	n = read(), m = read();
	for(int i = 1; i <= n; i++){
		int t;
		t = read();
		for(int j = 1; j <= t; j++){
			int a, b, c;
			a = read(), b = read(), c = read();
			f[a][b][c] |= 1<<i;
		}
	}
	for(int i = 1; i <= 400; i++)
		for(int j = 1; j <= 400; j++)
			for(int k = 1; k <= 400; k++)
				f[i][j][k] |= f[i-1][j][k]|f[i][j-1][k]|f[i][j][k-1];
	seed = read();
	std::mt19937 rng(seed);
	s[0] = 1;
	for(int i = 1; i <= m; i++)
		s[i] = 1ll*s[i-1]*seed%mod;
	long long ans = 0;
	for(int i = 1; i <= m; 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
	    int t = 0;
		for(int j = 1; j <= n; j++)
			if(f[IQ][EQ][AQ]&(1<<j))	
				t++;
//		printf("%d %d %d\n", IQ, EQ, AQ);
	    lastans = t;  // The answer to the i-th friend
		ans = (ans+1ll*lastans*s[m-i]%mod)%mod;
	}
	printf("%lld\n", ans);
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值