2023牛客暑期多校训练营7

HikariFears / 2023-08-15 / 原文

C.Beautiful Sequence

题意:有长为\(n\)的数组\(a\),通过操作\(a_i \oplus a_{i+1}\)得到\(b_i\),现在给出数组\(b\),求出字典序第\(k\)小的数组\(a\)

Solution

不难发现,如果确定了\(a_1\)的某一二进制位上的数,就可以确定整个数组\(a\)的这一位上的数,我们首先把所有的二进制位数都变为-1,表示这一位还未确定

对于两个相邻的数,如果它们以0经过异或处理后的某一位是\(x,y\)

\(x=y\),对答案没有影响

\(x>y\),则\(a_1\)的这一位必须是1

\(x<y\),则\(a_1\)的这一位必须是0

于是我们每次看一下前面是否有冲突即可

然后就是统计答案了,对于\(k\),我们也可以拆成二进制,来对\(a\)上的-1的位置进行修改即可

void solve()
{
    memset(a, -1, sizeof(a));
    int n, k;
    cin >> n >> k;
    for (int i = 2; i <= n; i++)
        cin >> b[i];
    for (int i = 2; i <= n; i++)
        c[i] = c[i - 1] ^ b[i];
    for (int i = 1; i < n; i++)
    {
        for (int j = 29; j >= 0; j--)
        {
            int k1 = (c[i] >> j)&1, k2 = (c[i + 1] >> j)&1;
            if (k1 == k2)
                continue;
            if (a[j] == -1)
                a[j] = k1;
            else if (a[j] != k1)
            {
                cout << "-1\n";
                return;
            }
            break;
        }
    }
    int temp = k - 1;
    for (int i = 0; i < 30; i++)
    {
        if (a[i] == -1)
        {
            a[i] = (temp & 1);
            //cout<<(temp&1)<<"\n";
            temp >>= 1;
        }
    }
    /*for(int i=29;i>=0;i--)cout<<a[i];
    cout<<"\n";*/
     
    if (temp)
    {
        cout << "-1\n";
        return;
    }
    int res = 0;
    for (int j = 29; j >= 0; j--)
    {
        res <<= 1;
        res += a[j];
    }
    for (int i = 1; i <= n; i++)
    {
        cout << (res ^ c[i]) << " \n"[i == n];
    }
}

G.Cyperation

题意:给出一个数组,把它看成一个环,每次可以选择环上最短距离为k的两个数,让它们都-1,问能否使得其变为全0

Solution

原数组可以看成若干个小环,令这个环为\(a_1,a_2,...,a_n\)

假设现在对\(a_1,a_2\)进行\(x\)次操作

后面要使得\(a_2\)归零,则还需对\(a_2,a_3\)进行\(a_2-x\)次操作

同理对\(a_3,a_4\)进行\(a3-(a2-x)\)次操作

...

依次类推,最后对\(a_n,a_1\)进行\(a_n-(a_{n-1}-...-(a_2-x))\)次操作

\(p_2=a_2,p_i=a_i-p_{i-1},p_1=a_1-p_n\),则有

\[\begin{cases} p_2-x\geq0\\ p_3+x\geq0\\ \vdots\\ p_n+(-1)^{n-1}x\geq0\\ \end{cases} \]

对于\(n\)为偶数情况,可以发现\(a_1-p_n=p_1=0\)

对于\(n\)为奇数情况,有\(2x=a_1-p_n=p_1\)

所以对于对应的情况判断一下,然后看\(x\)范围是否合法即可

bool check(vector<int> v)
{
    b[0] = 0;
    int n=v.size();
    for (int i = 1; i < n; i++)
    {
        b[i] = v[i] - b[i - 1];
    }
    b[0] = v[0] - b[n - 1];
    int l = 0, r = v[0];
    for (int i = 0; i < n; i++)
    {
        if (i & 1)
            r = min(r, b[i]);
        else
            l = max(l, -b[i]);
        if (l > r)
            return false;
    }
    if (n % 2 == 0)
        return b[0] == 0;
    else
    {
    	int x=b[0]/2;
    	return ((2*x==b[0])&&(l<=x&&x<=r));
    }
}
int n, k;
void solve()
{

    cin >> n >> k;
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
        vis[i] = 0;
    }
    int flag = 1;
    for (int i = 0; i < n; i++)
    {
        if (a[i] != 0)
        {
            flag = 0;
            break;
        }
    }
    if (flag)
    {
        cout << "YES\n";
        return;
    }
    if (k > n / 2)
    {
        cout << "NO\n";
        return;
    }

    for (int i = 0; i < n; i++)
    {
        if (vis[i])
            continue;
        vector<int> r;
        r.push_back(a[i]);
        int pos = (i + k) % n;
        while (pos != i)
        {
            r.push_back(a[pos]);
            vis[pos] = 1;
            pos += k;
            pos%=n;
        }
        //for(auto it:r)cout<<it<<" ";
     //   cout<<"\n";
        if (!check(r))
        {
            cout << "NO\n";
            return;
        }
    }
    cout << "YES\n";
}

I.We Love Strings

题意:给出一些由0,1,?组成的字符串,'?'既可以是1也可以是0,问有多少字符串能与之匹配

Solution

考虑到字符串总长不会超过400,如果字符串个数>20,则长度<20,反之亦然

对于长度<20的,我们可以暴力法求出个数,对于长度>20的,我们可以通过容斥原理来算出个数

int brute_get(vector<string> &v)
{
    if (v.size() == 0)
        return 0;
    int res = 0;
    int len = v[0].size();
    for (int j = 0; j < (1 << len); j++)
    {
        for (auto it : v)
        {
            int flag = 1;
            for (int i = 0; i < len; i++)
            {
                if (it[i] == '?' || it[i] - '0' == ((j >> i) & 1))
                {
                    continue;
                }
                else
                {
                    flag = 0;
                    break;
                }
            }
            if (flag)
            {
                res = (res + 1) % mod;
                break;
            }
        }
    }

    return res;
}

int inc_get(vector<string> &v)
{
    if (v.size() == 0)
        return 0;
    int res = 0;
    int len = v[0].size();
    int op;
    for (int i = 1; i < (1 << v.size()); i++)
    {
        int flag = 1;
        op = 0;
        string check(len, '?');
        for (int j = 0; j < v.size(); j++)
        {
            for (int k = 0; k < len; k++)
            {
                if (((i >> j) & 1) == 0)
                    continue;
                if (check[k] == '?')
                {
                    check[k] = v[j][k];
                }
                else if (check[k] != v[j][k] && v[j][k] != '?')
                {
                    flag = 0;
                    break;
                }
            }
        }
        if (!flag)
            continue;
        int cnt = 1;
        for (int k = 0; k < len; k++)
        {
            if (check[k] == '?')
                cnt = (cnt * 2) % mod;
        }
        int temp = i;
        while (temp > 0)
        {
            if (temp & 1)
                op ^= 1;
            temp >>= 1;
        }
        res = ((res + (2 * op - 1) * cnt % mod) % mod + mod) % mod;
    }

    return res;
}

void solve()
{
    int n;
    cin >> n;
    int ans = 0;
    for (int i = 1; i <= n; i++)
    {
        string t;
        cin >> t;
        e[t.size()].push_back(t);
    }
    for (int i = 1; i <= 400; i++)
    {
        if (i <= 20)
            ans = (ans + brute_get(e[i])) % mod;
        else
            ans = (ans + inc_get(e[i])) % mod;
    }
    cout << ans << "\n";
}