CF1017D Wu

1 CF1017D Wu

2 题目描述

时间限制 \(2s\) | 空间限制 \(256M\)

\(Childan\) 正在编造一个传奇故事来销售他的赝品-一条带有强烈 \(Wu\) 意识的项链给 \(Kasouras\)。但是 \(Kasoura\) 先生不相信这个故事,所以他要问几个关于 \(Childan\) 所谓个人珍藏的项链的问题。

这个个人珍藏是一个多重集 \(𝑆\)\(𝑚\)\(01\) 字符串。

\(01\) 字符串是包含 \(𝑛\) 个字符 \(“0”\)\(“1”\) 的字符串。例如,如果 \(𝑛=4\),则字符串 \(“0110”、“0000”\)\(“1110”\)\(01\) 字符串,但 \(“00110”\)(有 \(5\) 个字符,而不是 \(4\) 个)和 \(“0”\) 不是。

注意,多重集 \(𝑆\) 可以包含相等的元素。

\(Kasoura\) 先生通常会提供一个 \(01\) 字符串 \(𝑡\),并询问 \(Childan\) 在多重集 \(𝑆\) 中有多少个字符串 \(s\) 对应的 \((𝑠,𝑡)\)\(Wu\) 值不大于 \(𝑘\)

\(Kasoura\) 夫人和 \(Kasoura\) 先生认为,如果 \(𝑠_𝑖=𝑡_𝑖(1≤𝑖≤𝑛)\),则字符对的 \(Wu\) 值等于 \(𝑤_𝑖\),否则为 \(0\)\(01\) 字符串对的 \(Wu\) 值是每个字符对的 \(Wu\) 值的总和。请注意,每个\(01\) 字符串的长度等于 \(𝑛\)
例如,如果 \(𝑤=[4,5,3,6]\)\((“1001”、“1100”)\)\(Wu\)\(7\),因为这些字符串只在第一和第三位置上具有相等的字符,所以 \(𝑤_1+𝑤_3=4+3=7\)

你需要帮助 \(Childan\) 回答 \(Kasoura\) 先生的问题。即在多重集 \(𝑆\) 中找到对应的 \(Wu\) 值不大于 \(𝑘\) 的字符串的数量。

3 题解

我们首先观察到 \(n \le 12\),且题目中提到的字符串均为 \(01\) 串,可以考虑使用状态压缩。我们发现:对于长度为 \(12\) 的字符串,其可能的组合方案有 \(2^{12} = 4096\) 种,分别为从 \(0\)\(4095\)。但是,题目中的 \(m\) 小于等于 \(5 * 10^5\),明显大于 \(4096\)。这意味着,给出的字符串中可能有重复的字符串出现,而我们在统计答案时只需要考虑某一个字符串出现的次数,所以我们可以考虑去重并记录个数。

但是我们仍然无法保证时间上的高效:依照当前做法,我们对于每次询问都要遍历一遍 \(0\)\(4095\) 的所有 \(01\) 串并且遍历该字符串的长度以计算产生的价值,时间复杂度为 \(O(12 * 4096* q)\)。由于 \(1 \le q \le 5 * 10^5\),这样的算法仍然会超时。我们此时可以发现:\(q\) 也出现了大量重复的字符串。我们想到:如果我们直接从 \(0\)\( 4095\) 预处理出所有可能的字符串,并计算这些字符串与给出的 \(m\) 个字符串匹配所得出的价值,那么我们可以直接找到每次询问对应的字符串与 \(m\) 个字符串匹配的结果。但是这样我们仍然需要在 \(O(4096 * q)\) 的时间复杂度内找出所有答案小于等于 \(k\) 的字符串,仍然无法通过此题。

我们研究性质,发现一个十分关键的性质:对于我们预处理出的字符串,在计算时其与 \(m\) 个字符串的答案只需要统计数量,与答案的顺序无关,因此我们可以将这些答案递增排序。剩下的做法就十分清晰了:我们通过二分找出最大的小于等于 \(k\) 的答案,计算从第一个字符串到当前答案中的字符串的个数的和。而对于这个和,我们可以提前预处理出来,使用前缀和在 \(O(1)\) 的时间复杂度内查询。这样一来,每次查询的时间复杂度就是 \(O(log_2 4096)\),也就是 \(O(12)\)。整个代码的时间复杂度就是 \(O(12*q)\),可以通过此题。

4 代码(空格警告):

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 20;
const int M = 5000;
const int L = 5e5+10;
int n, m, q, x, x1, cnt, cnt2, cnt3, l, r, mid, ans, k, len;
int w[N], S[L], nu[M], ns[M];
struct node
{
    int ans, ms, sum;
    bool operator<(const node&x)const{return ans<x.ans;}
};
vector<node> v[M];
node y;
char s[N];
int main()
{
    scanf("%d %d %d", &n, &m, &q);
    for (int i = 1; i <= n; i++) scanf("%d", &w[i]);
    for (int i = 1; i <= m; i++)
    {
        x = 1;
        scanf("%s", s);
        len = strlen(s);
        for (int j = len-1; j >= 0; j--)
        {
            if (s[j] == '1') S[i] += x;
            x <<= 1;
        }
    }
    S[0] = 9360;
    sort(S+1, S+m+1);
    for (int i = 1; i <= m; i++)
    {
        if (S[i] != S[i-1])
        {
            ns[++cnt] = S[i];
            nu[cnt] = 1;
        }
        else nu[cnt]++;
    }
    for (int i = 0; i <= 4095; i++)
    {
        for (int j = 1; j <= cnt; j++)
        {
            cnt2 = 0;
            cnt3 = 0;
            x = i;
            x1 = ns[j];
            for (int k = 1; k <= n; k++)
            {
                if ((x & 1) == (x1 & 1)) cnt3 += w[n - cnt2];
                cnt2++;
                x >>= 1;
                x1 >>= 1;
            }
            y.ans = cnt3;
            y.ms = j;
            v[i].push_back(y);
        }
    }
    for (int i = 0; i <= 4095; i++) sort(v[i].begin(), v[i].end());
    for (int i = 0; i <= 4095; i++)
    {
        for (int j = 0; j < v[i].size(); j++)
        {
            if (j) v[i][j].sum += v[i][j-1].sum;
            v[i][j].sum += nu[v[i][j].ms];
        }
    }
    for (int i = 1; i <= q; i++)
    {
        cnt2 = 0;
        x = 1;
        scanf("%s %d", s, &k);
        len = strlen(s);
        for (int j = len-1; j >= 0; j--)
        {
            if (s[j] == '1') cnt2 += x;
            x <<= 1;
        }
        l = 0;
        r = v[cnt2].size()-1;
        while (l <= r)
        {
            mid = (l+r)/2;
            if (v[cnt2][mid].ans <= k)
            {
                ans = mid;
                l = mid+1;
            }
            else r = mid-1;
        }
        printf("%d\n", v[cnt2][ans].sum);
    }
    return 0;
}

欢迎关注我的公众号:智子笔记

posted @ 2021-02-06 18:18  David24  阅读(82)  评论(0编辑  收藏  举报