列表

详情


NC206080. 完美的战役

描述

在部落战争中,两个部落交战将各自从自己的所有分支中选择一些分支组成一支军队,为了提高军队的战力值,部落将对参战的分支进行训练,方式为将分支的战力值与一个任意正整数进行与操作,从而使得该军队的战力值是所选择的各个分支训练之后的战力值异或和,各个分支的战力值取决于该分支能组成的所有组合,一个组合的战力等于该组合的人数乘组合中每个人的战力和,而一个分支的战力值等于该分支所有可能组合的战力值的和。如果在战争中,部落双方的战力值相等则称为一场完美的战役。
现给出有 A、B 两个部落的具体情况,问是否无论 A 选取哪些分支组成军队,B部落总能相应的选出一些分支组成军队,从而出现完美战役的情况?

输入描述

输入包含多组数据,第一行包含一个数字 T(1 <= T <= 10) ,表示测试数据组数.接下来是 T 组数据,
每组数据第一行为两个整数 m, n(1 <= m,n <= 10) 分别表示 A、B 两个部落的分支数,
第二行包含 m 个整数 ,表示 A 部落每个分支的人数,
接下来 m 行,分别表示 A 部落第 i 个分支中第 j 个人的战力值为
接下来一行包含 n 个整数 ,表示 B 部落每个分支的人数,
接下来 n 行,分别表示 B 部落第 i 个分支中第 j 个人的战力值为

输出描述

每组数据输出包含一行,如果一定能够出现完美的战役,输出 “YES” ,否则,输出 “NO” ,不含引号。

示例1

输入:

1
2 2
2 2
1 2
1 3
2 2
1 4
2 4

输出:

YES

说明:

A 部落 1 号分支中的组合为 (p11,p12),(p11),(p12) ,分别的战力值为 (1+2) \times 21 \times 12 \times 1,故该分支的战力值为 9;
2 号分支的组合为 (p21,p22),(p21),(p22) ,分别的战力值为(1+3) \times 21 \times 13 \times 1 ,故该分支的战力值为 12;
故 A 部落能派出的部队战力值有 0,1,4,5,8,9,12,13。
对于 B 部落,能够派出的战力值有 [0,31] 中的整数.

示例2

输入:

2
2 1
2 2
1 2
1 3 
3
2 4 6
2 2
2 2
1 2
1 3
2 2
1 1
2 4

输出:

NO
NO

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++11(clang++ 3.9) 解法, 执行用时: 204ms, 内存消耗: 3684K, 提交时间: 2020-05-23 17:58:55

#include<cstdio>
long long bitA[200000], bitB[200000];
long long a[20], b[20];

void factor(long long u,long long bit[],long long offset){
    int size = offset;
    while(u){
        bit[size++] |= u%2;
        u /= 2;
    }
}

int main(){
    int T;
    scanf("%d",&T);
    while(T--){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i = 0; i <= 200000; i++) bitA[i] = bitB[i] = 0;
    for(int i = 0; i < n; i++) scanf("%lld",&a[i]);
    for(int i = 0; i < n; i++){
        long long k = a[i];
        long long sum = 0;
        for(int j = 0; j < k; j++){
            long long u;
            scanf("%lld",&u);
            sum += u;
        }
        int offset = k-2;
        if(k==1) offset = 0, k = 0;
        long long mask = (k+1)*sum;
        factor(mask,bitA,offset);
    }
    for(int i = 0; i < m; i++) scanf("%lld",&b[i]);
    for(int i = 0; i < m; i++){
        long long k = b[i];
        long long sum = 0;
        for(int j = 0; j < k; j++){
            long long u;
            scanf("%lld",&u);
            sum += u;
        }
        int offset = k-2;
        if(k==1) offset = 0, k = 0;
        long long mask = (k+1)*sum;
        factor(mask,bitB,offset);
    }
    int find = 0;
    for(int i = 0; i <= 200000; i++){
        if(bitA[i] && !bitB[i]) find = 1;
    }
    if(!find) printf("YES\n");
    else printf("NO\n");
    }
    return 0;
}

C++14(g++5.4) 解法, 执行用时: 133ms, 内存消耗: 616K, 提交时间: 2020-05-23 16:33:31

#include <iostream>
#include <string>
#include <vector>
#include <cstring>

using namespace std;

const int maxn = 1e5 + 500;

int sz[2];
bool isok[maxn][2];
int num[200][2];

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T;
    cin >> T;
    while (T--) {
        memset(isok, 0, sizeof isok);

        cin >> sz[0] >> sz[1];
        for (int cas = 0; cas <= 1; ++cas) {
            for (int i = 0; i < sz[cas]; ++i) {
                cin >> num[i][cas];
            }
            for (int i = 0; i < sz[cas]; ++i) {
                int temp;
                int sum = 0;
                for (int j = 0; j < num[i][cas]; ++j) {
                    cin >> temp;
                    sum += temp;
                }
                int suffnum = num[i][cas] - 2;
                long long pre = 1ll * (num[i][cas] + 1) * sum;
                for (int j = 0; j < 60; ++j) {
                    int bit = j + suffnum;
                    if ((pre >> j) & 1) {
                        isok[bit][cas] = true;
                    }
                }
            }
        }
        int suc = 1;
        for (int i = 0; i < 1e5 + 300; ++i) {
            if (isok[i][0] && !isok[i][1]) {
                suc = 0;
            }
        }
        if (suc) cout << "YES" << endl;
        else cout << "NO" << endl;
    }
    return 0;
}

上一题