Stay Hungry,Stay Foolish!

C - Keys

C - Keys

https://atcoder.jp/contests/abc356/tasks/abc356_c

 

思路

对于样例1中的两种情况,可以推知如下推论:

(1)1 2为real keys

(2)1 3 为real keys

(3)上面两个不能同为真。

所以,上述可能得真钥匙组合为(1)(2),注意是可能,不是全部都是成立。

 

更一般的情况,可以把测试用例分为 正测试样例 和 负测试样例

正测试样例, 测试key集中, 必须包含 real keys(至少K个), 还可能包含 dummy keys 。

负测试样例, 测试key集中 , 可能包含 dummy keys,  也可能包含 real keys(必须小于K个)。

 

对于任何一组真钥匙的组合C(选择真钥匙的一结果), 要保证跟 任何 正测试样例 和 负测试样例 都没有矛盾,

则必须要保证:

(1)任一正测试样例, 组合C跟此正测试样例的钥匙交集必须包含至少K个钥匙,这些钥匙也属于组合C,顾都是真钥匙,支持此测试样例成立。

(2)任一负测试样例, 组合C跟此负测试样例的钥匙交集必须包含不多于K个钥匙, 这些钥匙也属于组合C,顾都是真钥匙,不破坏此测试样例成立性。

 

 

 

 

Code

https://atcoder.jp/contests/abc356/submissions/54250649

int n,m,k;


int main()
{
    cin >> n >> m >> k;
    
    vector<int> a(m);
    vector<bool> r(m);
    
    for(int i=0; i<m; i++){
        int c;
        cin >> c;
        
        for(int j=0; j<c; j++){
            int key;
            cin >> key;
            key--;

            a[i] |= 1 << key;
        }
        
        char test;
        cin >> test;
        
        r[i] = test == 'o'? true : false;
    }

    // iterate all combinations
    int maxc = 1 << n;
    int ans = 0;
    for(int i=0; i<maxc; i++){
        bool contradict = false;
        
        for(int j=0; j<m; j++){
            int overlap = i & a[j];
            
            // count 1 number
            int keycnt = 0;
            while(overlap){
                if (overlap & 1){
                    keycnt++;
                }
                
                overlap >>= 1;
            }
            
            if (r[j] && keycnt>=k){
                continue;
            }else if (!r[j] && keycnt<k){
                continue;
            }
            
            contradict = true;
            break;
        }
        
        if (!contradict){
            ans++;
        }
    }

    cout << ans << endl;

    return 0;
}

 

Code (文心一言)

现在大模型的推理能力还是很强悍的,给出的代码仅仅有两个bug,修正后pass。

原始代码:

#include <iostream>  
#include <vector>  
#include <bitset>  
  
using namespace std;  
  
// 函数用于计算一个整数中二进制1的个数  
int countOnes(int mask) {  
    int count = 0;  
    while (mask) {  
        count += mask & 1;  
        mask >>= 1;  
    }  
    return count;  
}  
  
// 函数用于检查一个mask是否在给定的keys集合中至少有K个1  
bool checkAtLeastKOnes(int mask, const vector<int>& keys, int K) {  
    int count = 0;  
    for (int key : keys) {  
        // 检查mask的对应位是否为1  
        if (mask & (1 << (key - 1))) {  
            count++;  
        }  
    }  
    return count >= K;  
}  
  
// 函数用于检查一个mask是否在给定的keys集合中至多有K-1个1  
bool checkAtMostKMinusOneOnes(int mask, const vector<int>& keys, int K) {  
    int count = 0;  
    for (int key : keys) {  
        // 检查mask的对应位是否为1  
        if (mask & (1 << (key - 1))) {  
            count++;  
        }  
    }  
    return count <= K - 1;  
}  
  
int main() {  
    int N, M, K;  
    cin >> N >> M >> K;  
  
    vector<pair<vector<int>, char>> tests(M);  
    for (int i = 0; i < M; ++i) {  
        int C;  
        cin >> C;  
        tests[i].first.resize(C);  
        for (int j = 0; j < C; ++j) {  
            cin >> tests[i].first[j];  
        }  
        cin >> tests[i].second;  
    }  
  
    vector<int> dp(1 << N, 0); // dp数组大小为2^N  
  
    // 初始化dp数组  
    for (int mask = 0; mask < (1 << N); ++mask) {  
        if (countOnes(mask) >= K) {  
            dp[mask] = 1;  
        }  
    }  
  
    // 根据测试更新dp数组  
    for (const auto& test : tests) {  
        const vector<int>& keys = test.first;  
        char result = test.second;  
  
        for (int mask = 0; mask < (1 << N); ++mask) {  
            if (dp[mask] == 0) continue; // 如果这个状态已经被排除了,就跳过  
  
            if (result == 'o' && !checkAtLeastKOnes(mask, keys, K)) {  
                dp[mask] = 0; // 如果结果应该是'o'但mask中1的数量不足K个,排除这个状态  
            }  
            if (result == 'x' && checkAtMostKMinusOneOnes(mask, keys, K)) {  
                dp[mask] = 0; // 如果结果应该是'x'但mask中1的数量超过或等于K个,排除这个状态  
            }  
        }  
    }  
  
    // 计算答案  
    int answer = 0;  
    for (int mask = 0; mask < (1 << N); ++mask) {  
        if (dp[mask] == 1) {  
            answer++;  
        }  
    }  
  
    cout << answer << endl;  
  
    return 0;  
}

 

改正两个bug后的代码:

https://atcoder.jp/contests/abc356/submissions/54249838

#include <iostream>
#include <vector>
#include <bitset>

using namespace std;

// 函数用于计算一个整数中二进制1的个数
int countOnes(int mask) {
    int count = 0;
    while (mask) {
        count += mask & 1;
        mask >>= 1;
    }
    return count;
}

// 函数用于检查一个mask是否在给定的keys集合中至少有K个1
bool checkAtLeastKOnes(int mask, const vector<int>& keys, int K) {
    int count = 0;
    for (int key : keys) {
        // 检查mask的对应位是否为1
        if (mask & (1 << (key - 1))) {
            count++;
        }
    }
    return count >= K;
}

// 函数用于检查一个mask是否在给定的keys集合中至多有K-1个1
bool checkAtMostKMinusOneOnes(int mask, const vector<int>& keys, int K) {
    int count = 0;
    for (int key : keys) {
        // 检查mask的对应位是否为1
        if (mask & (1 << (key - 1))) {
            count++;
        }
    }
    return count <= K - 1;
}

int main() {
    int N, M, K;
    cin >> N >> M >> K;

    vector<pair<vector<int>, char>> tests(M);
    for (int i = 0; i < M; ++i) {
        int C;
        cin >> C;
        tests[i].first.resize(C);
        for (int j = 0; j < C; ++j) {
            cin >> tests[i].first[j];
        }
        cin >> tests[i].second;
    }

    vector<int> dp(1 << N, 0); // dp数组大小为2^N

    // 初始化dp数组
    for (int mask = 0; mask < (1 << N); ++mask) {
        if (1) {
            dp[mask] = 1;
        }
    }

    // 根据测试更新dp数组
    for (const auto& test : tests) {
        const vector<int>& keys = test.first;
        char result = test.second;

        for (int mask = 0; mask < (1 << N); ++mask) {
            if (dp[mask] == 0) continue; // 如果这个状态已经被排除了,就跳过

            if (result == 'o' && !checkAtLeastKOnes(mask, keys, K)) {
                dp[mask] = 0; // 如果结果应该是'o'但mask中1的数量不足K个,排除这个状态
            }
            if (result == 'x' && !checkAtMostKMinusOneOnes(mask, keys, K)) {
                dp[mask] = 0; // 如果结果应该是'x'但mask中1的数量超过或等于K个,排除这个状态
            }
        }
    }

    // 计算答案
    int answer = 0;
    for (int mask = 0; mask < (1 << N); ++mask) {
        if (dp[mask] == 1) {
            answer++;
        }
    }

    cout << answer << endl;

    return 0;
}

 

posted @ 2024-06-06 00:28  lightsong  阅读(5)  评论(0编辑  收藏  举报
Life Is Short, We Need Ship To Travel