洛谷P9017 [USACO23JAN] Lights Off G题解

咕咕了好久呢,这是纯自己写的,没有借鉴别人的代码啦

最气人的是从打比赛那时候开始就一直是一种理解错题意的状态很烦,还以为每次要从123里面选一个出来执行

考虑将开关状态拆开考虑,这是因为对开关状态的影响就是异或一下,所以有几次一开始异或几次就好了(注意循环移位)

最多3n次是显然的.不过我们可以注意到最多只需要2n次,因为对于开关的每一位数字,2n次都进行了两个循环,每个位置上都被异或两次抵消了

注意如果在计算当前值时更新后者复杂度会比寻找前者来更新当前低,因为寻找前者产生了O(n)的复杂度

也就是类似BFS

#include <iostream>
#include <cmath>
#include <vector>
#include <cstring>
#include <cstdio>
#include <queue>
#include <algorithm>
#include <stack>
#define debug(x) cout << #x << '=' << x << endl;

using namespace std;
const int maxN = 20;
const int maxn = pow(2, maxN) + 5;
bool dp[2 * maxN + 5][maxn];                   // dp[i][j]表示i次后能否用00...0来使得灯全关
int n, t, consecutiveOnes[maxN + 5][maxN + 5]; // from和len
struct Node
{
    int dis;
    int val;
};
queue<Node> q;
int rotate_right(int x)
{
    int last = x & 1;
    x >>= 1;
    x |= (last << (n - 1));
    return x;
}
int rotate_left(int x)
{
    int first = x & (1 << (n - 1));
    first = (first != 0);
    x <<= 1;
    x |= first;
    x &= (1 << n) - 1;
    return x;
}
int fillOnes(int from, int to)
{
    int tmp = 0;
    if (from >= to)
    {
        for (int i = from; i >= to; --i)
            tmp |= 1 << (i - 1);
    }
    else
    {
        for (int i = from; i >= 1; --i)
            tmp |= 1 << (i - 1);
        for (int i = n; i >= to; --i)
            tmp |= 1 << (i - 1);
    }
    return tmp;
}
int getValNext(int now, int from, int len)
{
    if (len > n)
        len -= n;
    return now ^ consecutiveOnes[from][len];
}
int calculate(int light, int lightSwitch)
{
    /* debug(light); */
    for (int step = 0; step <= 2 * n; ++step)
    {
        /* debug(step); */
        if (dp[step][light])
            return step;
        light ^= lightSwitch;
        lightSwitch=rotate_right(lightSwitch);
    }
}
inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=(x<<1)+(ch^48);
        ch=getchar();
    }
    return x*f;
}
int main()
{
    cin >> t >> n;
    for (int from = 1; from <= n; ++from) // 高位为n,低位为1
        for (int len = 1; len <= n; ++len)
        {
            int to = from - len + 1;
            if (to <= 0)
                to += n;
            consecutiveOnes[from][len] = fillOnes(from, to);
        }
    dp[0][0] = 1;
    q.push(((Node){0, 0}));
    while (!q.empty())
    {
        Node node = q.front();
        q.pop();
        int disNext = node.dis + 1;
        if (disNext > 2 * n)
            continue;
        int valNow = node.val;
        int valPrepare = rotate_right(valNow);
        /* debug(valNow);
        debug(valPrepare);
        debug(disNext); */

        for (int i = n; i >= 1; --i)
        {
            int valNext = getValNext(valPrepare, i, disNext);
            /* debug(valNext); */
            if (!dp[disNext][valNext])
            {
                /* cout << "PUSH";
                debug(valNext); */
                dp[disNext][valNext] = true;
                q.push(((Node){disNext, valNext}));
            }
        }
    }
    /* for (int j = 0; j <= 2 * n; ++j, cout << endl)
        for (int i = 0; i < (1 << n); ++i)
            cout << dp[j][i] << ' '; */
    while (t--)
    {
        int a=read(), b=read();
        cout << calculate(a, b) << endl;
    }
    return 0;
}

posted @ 2023-03-10 01:30  520Enterprise  阅读(37)  评论(0编辑  收藏  举报