BZOJ 1141 [POI2009]Slw 分类讨论

题意:链接

方法:分类讨论

解析:

Idea rozwiązania wzorcowego polega na przekształcaniu danego ciągu w = (k1,…, kn) przez
coś w rodzaju funkcji odwrotnej do h. Okazuje się, że dla dużych elementów ciągu w cofanie
funkcji h polega na zwykłym ich zmniejszaniu, a dla małych (nie większych niż 3) trzeba
czasem rozpatrywać pewne przypadki szczególne. Operacje wykonywane w algorytmie mają
tę własność, że ciąg dobry przekształcają w ciąg dobry, a zły — w zły. Proces ten doprowadza
w końcu do ciągu jednoelementowego, który oczywiście jest dobry (wtedy ciąg początkowy
też był dobry), lub do ciągu, o którym potrafimy stwierdzić, że na pewno jest zły (wtedy
początkowy był zły).
w:=(k1,…,kn)
while |w|>1 do begin
if w zawiera fragment k,0 dla k ∈ {1,3} then return false
Wykonaj kolejno następuj ące operacje na ciągu w:
zamien, je ´ zeli wyst˛epuje, pierwszy element 0 ˙ → 2
zamien, je ´ zeli wyst˛epuje, ostatni element 3 ˙ → 2
usun, je ´ zeli wyst˛epuje, ostatni element równy 1 ˙
zamien wszystkie fragmenty 1 ´ ,0 → 2
zamien wszystkie fragmenty 3 ´ ,0 → 2,2
zmniejsz wszystkie elementy o 1

看懂上面的波兰文你就AC了。

其实翻译过来大概是这个意思。

我们可以不断的将连接起来的串进行逆转换。

然后伪代码具体给出了方式。

如果当前序列仅剩一个元素则为可行。

如果在序列中存在一个元素为零,则如果他前面的元素不是1或3,则返回0.

这是为什么呢?

首先对于本题来说,显然我们可以通过手画来搞出来几个数据,然后我们可以发现其实所有的串是个斐波那契形式

每一个是上一个与上上一个的连接。

zamien, je ´ zeli wyst˛epuje, pierwszy element 0 ˙ → 2

上面那句话的意思是如果首位是0的话那么把它转成2.

zamien, je ´ zeli wyst˛epuje, ostatni element 3 ˙ → 2

上面那句话的意思是如果末位是3的话那么把它转成2.

然后就是什么找序列中有0的数

如果前一个是1,则用2替换两个数。

如果前一个是3,则用3替换两个数

然后所有元素-1,递归就好了。

这是为什么呢?

观察下表

3->101

5->10110101

其实总的规律就是什么两个0不能连起来啊

不能有101010这种串什么的。

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 100100
using namespace std;
int n;
int a[N];
int check()
{
    while(n>1)
    {
        if(!a[1])a[1]=2;
        if(a[n]==1)a[n]=-1;
        else if(a[n]==3)a[n]=2;
        for(int i=2;i<=n;i++)
        {
            if(!a[i])
            {
                if(a[i-1]==1)a[i]=-1,a[i-1]=2;
                else if(a[i-1]==3)a[i]=a[i-1]=2;
                else return 0;
            }
        }
        int m=0;
        for(int i=1;i<=n;i++)
        {
            if(a[i]!=-1)a[++m]=a[i];
        }
        n=m;
        for(int i=1;i<=n;i++)a[i]--;
    }
    return 1;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        puts(check()?"TAK":"NIE");
    }
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值