BZOJ1080 暴力+位移运算符的用法

1080: [SCOI2008]劣质编码

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 337  Solved: 148
[Submit][Status][Discuss]

Description

  一个编码方案把每个字符对应到一个01串。例如{1,1010,01,10101}就是一个编码方案,它把四个字符(假设
它们为a,b,c,d)分别对应到串1、1010,01,10101。字符串的编码为各字符编码的连接。例如,在刚才的编码方
案中,字符串cac的编码为01101,dcb的编码为10101011010。 进一步分析发现,刚才的编码是相当劣质的,因为
字符串ba, acc和d的编码都是10101。对于一个编码方案,你的任务是找出三个不同的字符串,使得它们的编码全
相同。换句话说,找一个01编码串,使得它至少有三种解码方式。如果有多组解,这个编码串应当尽量短。

Input

  第一行包含一个整数n,即符号的个数。以下n行每行为一个长度不超过50的01串(可能为空串),即各符号的
编码。

Output

  仅一行,包含一个整数,即最短编码的长度。如果无解,输出-1。

Sample Input

4

1

1010

01

10101

Sample Output

5

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<string>
#include<map>
using namespace std;
typedef vector<int> ve;
map<ve,int>hash;
queue<ve>Q;
string s[35];
int n;
void work(){
    ve u,v,t;
    for(int i=1;i<=n;++i)
    if(s[i]=="") {puts("0");exit(0);}
    else u.push_back(i<<6);
    hash[u]=0;
    Q.push(u);
    while(!Q.empty()){
        u=Q.front();
        Q.pop();
        int x=hash[u],cnt;
        for(int ch=‘0‘;ch<=‘1‘;++ch){
            cnt=0;
            v.clear();
            for(int i=0;i<(int)u.size();++i){
                int which=u[i]>>6,where=u[i]&63;
                if(s[which][where]^ch) continue;
                if(++where==s[which].size()) {
                    ++cnt;
                    for(int j=1;j<=n;++j) v.push_back(j<<6);
                }
                else v.push_back(which<<6|where);
            }
            if(cnt>=3) {printf("%d\n",x+1);exit(0);}
            sort(v.begin(),v.end());
            t.clear();
            for(int i=0;i<v.size();++i)
                if(i<2||v[i]^v[i-2]) t.push_back(v[i]);     //必须是i<m(m>=2)的形式,因为题干要求3个即可退出
            int &th=hash[t];
            if(t.size()&&!th) th=x+1,Q.push(t);
        }
    }
    puts("-1");
}
int main(){
   scanf("%d",&n);
   for(int i=1;i<=n;++i) cin>>s[i];
   work();
   return 0;
}

#include<cstdio>

#include<cstring>

#include<iostream>

#include<algorithm>

#include<vector>

#include<queue>

#include<string>

#include<map>

using namespace std;

typedef vector<int> ve;

map<ve,int>hash;

queue<ve>Q;

string s[35];

int n;

void work(){

    ve u,v;

    for(int i=1;i<=n;++i)

    if(s[i]=="") {puts("0");exit(0);}

    else u.push_back(i<<6);

    hash[u]=0;

    Q.push(u);

    while(!Q.empty()){

        u=Q.front();

        Q.pop();

        int x=hash[u],cnt;

        for(int ch=‘0‘;ch<=‘1‘;++ch){

            cnt=0;

            v.clear();

            for(int i=0;i<(int)u.size();++i){

                int which=u[i]>>6,where=u[i]&63;

                if(s[which][where]^ch) continue;

                if(++where==s[which].size()) {

                    ++cnt;

                    for(int j=1;j<=n;++j) v.push_back(j<<6);

                }

                else v.push_back(which<<6|where);

            }

            if(cnt>=3) {printf("%d\n",x+1);exit(0);}

            sort(v.begin(),v.end());   //也可以直接将v压入队列,但是要先排序

            int &th=hash[v];

            if(v.size()&&!th) th=x+1,Q.push(v);

        }

    }

    puts("-1");

}

int main(){

   scanf("%d",&n);

   for(int i=1;i<=n;++i) cin>>s[i];

   work();

   return 0;

}

时间: 2024-10-06 17:28:03

BZOJ1080 暴力+位移运算符的用法的相关文章

【Java中各运算符的用法】

Java的运算符可分为4类:算术运算符.关系运算符.逻辑运算符和位运算符. 1.算术运算符 Java的算术运算符分为一元运算符和二元运算符.一元运算符只有一个操作数:二元运算符有两个操作数,运算符位于两个操作数之间.算术运算符的操作数必须是数值类型. (1)一元运算符: 一元运算符有:正(+).负(-).加1(++)和减1(--)4个. 加1.减1运算符只允许用于数值类型的变量,不允许用于表达式中.加1.减1运算符既可放在变量之前(如++i),也可放在变量之后(如i++),两者的差别是:如果放在

Java补码表和位移运算符

在java中数据都是以二进制的形式保存的. 但是我们看到的数据怎么是10进制的? 因为java展示之前会自动调用toString()方法 这里以4位2进制为例,4位2进制只能表示16个数,即0-15.但是自然界的数不只是只有正数,还有负数,怎么表示呢? 所以java采用如下方式表示,见下图: 如果按照上面的补码计算,那么7+1的结果结果就为-8,7+2的结果为-9: 底层存储的是二进制,但是通过显示给用户的就是对应的数 7用二进制表示为0111,加1后为1000,java底层保存的是二进制码为1

Lua中..和#运算符的用法

Lua中..和#运算符的用法 样例 试试以下的样例就明确了在Lua编程语言提供的其它运算符: a = "Hello " b = "World" print("Concatenation of string a with b is ", a..b ) print("Length of b is ",#b ) print("Length of b is ",#"Test" ) 当建立并运行上

PHP 位移运算符(&lt;&lt;左移和&gt;&gt;右移)

位移运算符 << 位左移 左移运算的实质是将对应的数据的二进制值逐位左移若干位,并在空出的位置上填0,最高位溢出并舍弃.例 如 $a=10; $b=$a<<2; 则$b=40,根据手册描述可以看出位运算可以看出向左移一位,则是实现乘2运算.由于位移操作的运算速度比乘法的 运算速度高很多.因此在处理数据的乘法运算的时,采用位移运算可以获得较快的速度. 提示 将所有对2的乘法运算转换为位移运算,可提高程序的运行效率 示例: 以下三种表达方式是一个意思. $a = 1024; for($

python运算符与用法

运算符与用法 运算符 名称 说明 例子 + 加 两个对象相加 3 + 5得到8.'a' + 'b'得到'ab'. - 减 得到负数或是一个数减去另一个数 -5.2得到一个负数.50 - 24得到26. * 乘 两个数相乘或是返回一个被重复若干次的字符串 2 * 3得到6.'la' * 3得到'lalala'. ** 幂 返回x的y次幂 3 ** 4得到81(即3 * 3 * 3 * 3) / 除 x除以y 4/3得到1(整数的除法得到整数结果).4.0/3或4/3.0得到1.3333333333

JavaScript中instanceof运算符的用法以及和typeof的区别

instanceof : 为判断一个对象是否为某一数据类型,或一个变量是否为一个对象的实例;返回boolean类型栗子①: <script type="text/javascript"> var aColors = ["red", "green", "blue"]; alert(typeof aColors[0]); //output "string" alert(aColors[0] inst

PHP 的 &lt;&lt; 和 &gt;&gt; 位移运算符

先举两个例子 1 $b = 10; 2 $b = $b << 3; 3 echo $b; //输出 80 $b = 10; $b = $b >> 3; echo $b; //输出 1 可以发现  左位移会乘以相应的数   而 右位移会除以相应的数 如果得出浮点数,舍掉小数位,只取整数,位移运算其实是对二进制数的操作 位移运算符 << 位左移 左移运算的实质是将对应的数据的二进制值逐位左移若干位,并在空出的位置上填0,最高位溢出并舍弃.例 如$a=10;$b=$a<

JavaScript 无符号位移运算符 &gt;&gt;&gt; 三个大于号 的使用方法

JavaScript 无符号位移运算符 >>> 三个大于号 的使用方法 JavaScript中的无符号位移运算符是用三个大于号来表示的 计算方法 例 100>>>2 100的二进制是 01100100 向右移2位后为 00011001 最后结果为25 100>>>2==25 无符号位移(>>>)和有符号位移(>>)的区别是 有符号位移运算时如果数字为正数时位移后在前面补0,为负数时则在位移后在前面补1 例 100>&

JS逗号运算符的用法详解

逗号运算符的用法详解 注意: 一.由于目前正在功读JavaScript技术,所以这里拿JavaScript为例.你可以自己在PHP中试试. 二.JavaScript语法比较复杂,因此拿JavaScript做举例. 最近重新阅读JavaScript权威指南这本书,应该说很认真的阅读,于是便想把所学的东西多记录下来.后 面本人将逐步写上更多关于本书的文章. 本文的理论知识来自于JavaScript权威指南,我这里做一下整理,或者说叫笔记. 如果你的基础够好的话,完全理解不成问题,但是如果读得有些郁闷