GCJ Qualification Round 2015 Problem C. Dijkstra

因为一个疏忽改了好久,写的很冗长,反正过了就不管了,题目本身不难

由于运算满足结合律,所以 长度为 L*X 的运算 的结果一定要等于 i*j*k = -1

小数据的话从头走,记录 head[i] 表示 s[0] * s[1] * ... * s[i]
同理 tail[i] = s[L*X-1-i] * ... * s[L*X-1]
目标就是找到 head[l] = 'i',tail[r] = 'k' (l < L*X-1-r)
显然如果存在 l, r 的话,那就一定有解 (因为 [l, r] 中间的结果一定是 ‘j’)
O(n) 遍历 newL = L*X 就行了

接下来研究大数据
假设 S = s[0] * s[1] * ... * s[L-1]
显然有 l = S^k + l2 (k<X, l2<L),因为可以观察到 S^k 是有周期性的
可以优化一下 0<=k<min(X, 4)
这时候 newL = min(X, 4)*L
把小数据的代码改一下就行了

#include <iostream>
#include <string>

using namespace std;

const int maxn = 40010;

typedef long long ll;

int T;
ll L, X;
string s;

//i=2, j=3, k=4
int mat[5][5] = {
    {0, 0, 0, 0, 0},
    {0, 1, 2, 3, 4},
    {0, 2, -1, 4, -3},
    {0, 3, -4, -1, 2},
    {0, 4, 3, -2, -1} 
};

int chartoijk(char x)
{
    return x-'i'+2;
}

int a[maxn];
int head[maxn];
int tail[maxn];

int main()
{

    // freopen("a.in", "r", stdin);
    // freopen("b2.out", "w", stdout);

    cin>>T;
    for (int kase = 1; kase <= T; kase++)
    {
        cin>>L>>X;
        cin>>s;
        printf("Case #%d: ", kase);

        //长度不够
        if (L*X < 3)
        {
            puts("NO");
            continue;
        }

        for (int i = 0; i < L; ++i)
            a[i] = chartoijk(s[i]);

        for (int i = 1; i < min(X, (ll)4); ++i)
            for (int j = 0; j < L; ++j)
                a[i*L + j] = a[j];

        ll newL = L*min(X, (ll)4);

        int p = head[0] = a[0], q, tmp;
        for (int i = 1; i < newL; ++i)
        {
            q = a[i];
            tmp = mat[abs(p)][q];
            if (p < 0)  tmp = -tmp;
            p = tmp;
            head[i] = p;
        }

        if (head[X%4*L-1] != -1)
        {
            puts("NO");
            continue;
        }

        p = tail[0] = a[newL-1];
        for (int i = 1; i < newL; ++i)
        {
            q = a[newL-1-i];
            tmp = mat[q][abs(p)];
            if (p < 0)  tmp = -tmp;
            p = tmp;
            tail[i] = p;
        }

        int l=0, r=0;
        bool ans = false;
        while(l < (L*X-1-r))
        {
            if (head[l] != 2)
            {
                l++;
                continue;
            }

            while( l<(L*X-1-r) && r<newL && tail[r]!=4) 
                r++;

            if (l<(L*X-1-r) && r<newL)
            {
                ans = true;
                break;
            }
        }

        printf("%s\n", ans ? "YES" : "NO");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值