2022年牛客多校第四场补题

2022年牛客多校第四场补题

D.Jobs (Easy Version)

题意

q q q个人找工作,有 n n n家公司,每家公司有 m m m个工作,每个人和每一份工作都有 3 3 3个属性 a , b , c a,b,c abc,当且仅当每个人的 a , b , c a,b,c abc都大于某一份工作的 a , b , c a,b,c abc,这个人才能成功完成这个工作,如果一个人能完成某公司的一项工作,那么这个公司就会要他。每个人的属性都是由给你的 s e e d seed seed作为随机数的种子和上一个人的答案,进行随机生成。

计算

( ∑ i = 1 n a n s i ∗ s e e d q − i ) m o d 998244353 (\sum_{i =1}^n ans_i * seed ^ {q - i}) mod998244353 (i=1nansiseedqi)mod998244353

a n s i ans_i ansi表示第i个人有多少公司愿意接纳他

数据范围

1 ⩽ n ⩽ 10 1 \leqslant n \leqslant 10 1n10

1 ⩽ q ⩽ 2 ∗ 1 0 6 1 \leqslant q \leqslant 2 * 10 ^ 6 1q2106

1 ⩽ m ⩽ 1 0 5 1 \leqslant m \leqslant 10^5 1m105

1 ⩽ a i , b i , c i ⩽ 400 1 \leqslant a_i, b_i, c_i \leqslant 400 1ai,bi,ci400

思路

由于有 q q q个人了,那么查询一个人的答案的时间复杂度就要在 log ⁡ ( m ∗ n ) \log{(m * n)} log(mn),能想到先预处理出对于公司 i i i某个能力的值能否胜任, 然后 O ( 1 ) O(1) O(1)进行查询。

预处理,开四维的 b o o l bool bool数组会爆内存,所以用 b i t s e t bitset bitset进行压位, d p dp dp一下: d p [ i ] [ a ] [ b ] [ c ] dp[i][a][b][c] dp[i][a][b][c]一个人的能力属性值为 a , b , c a, b, c a,b,c能否胜任公司 i i i

时间复杂度

O ( n ∗ 40 0 3 ) O(n * 400 ^ 3) O(n4003)

可以优化的地方

  • 1.可以优化成三维的

  • 2.语言选择 C + + ( g + + 7.5.0 ) C++(g++ 7.5.0) C++(g++7.5.0),选 C + + ( c l a n g + + 11.0.1 ) C++(clang++ 11.0.1) C++(clang++11.0.1)就超时了。

  • 3.中间的快速幂可以先预处理出来可以少个 l o g log log

代码:

#include <bits/stdc++.h>
#pragma gcc optimize("O2")
#pragma g++ optimize("O2")
//#define int long long
#define endl '\n'
using namespace std;


const int N = 2e5 + 10, MOD = 998244353;
int n, q, x, y, z;
int k1,k2,k3,k4;
bitset<402>fk[11][401][401];
inline int getid(int x,int y,int z){
    return 160801*(x)+(y)*(401)+z;
}
int getans(int iq, int eq, int aq){
    int ans=0;
    for(int i=1;i<=n;i++){
        ans+=fk[i][iq][eq][aq];
    }
    return ans;
}

int binpow(long long x, int y, int mod, long long res = 1){
    for (; y; y >>= 1, (x *= x) %= mod) if (y & 1) (res *= x) %= mod;
    return res;
}

int powq[2000010];

inline void solve(){
    cin >> n >> q;
    for(int i = 1; i <= n; i++){
        cin >> k1;
        for(int j = 1; j <= k1; j++) {
            cin>>x>>y>>z;
            fk[i][x][y][z]=1;
        }
    } 
    
    for(short i=1;i<=n;i++){
        for(short j=1;j<=400;j++){
            for(short k=1;k<=400;k++){
                for(short x=1;x<=400;x++){
                    fk[i][j][k][x]=fk[i][j][k][x]|fk[i][j][k][x-1]|fk[i][j][k-1][x]|fk[i][j-1][k][x];
                }
            }
        }
    }
    int seed; cin >> seed;
    powq[0] = 1;
    for(int i = 1; i <= 2000000 + 5; i++){
        powq[i] = 1ll * powq[i - 1] * seed % MOD;
    }
    std::mt19937 rng(seed);
    std::uniform_int_distribution<> u(1, 400);
    int lastans = 0, ans = 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 = getans(IQ, EQ, AQ);           // The answer to the i-th friends
        (ans += (1ll * lastans * powq[q - i] % MOD)) %= MOD;
    }
    cout << (ans % MOD) << endl;
}

signed main(){
    
    ios_base::sync_with_stdio(false), cin.tie(0);
    cout << fixed << setprecision(12);
    int t = 1;
    while(t--) solve();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值