出题人罗哲正是神爷 Orz

Description

  这是一道披着交互题外衣的通信题,只支持 C++。

  你需要实现 \(2\) 个函数。

  交互库先给第一个函数传入一个参数 \(n\),你加密得到的 \(01\) 字符串的长度必须是 $n。你需要根据 \(n\) 做一些相应的预处理,并向交互库返回你能接受的最大 \(\text{long long}\) 类型整数 \(m\)。

  先根据你返回的 \(m\) 给分。若 \(m_{you}\gt m_{ans}\) 则你得 \(0\) 分,若 \(m_{you}=m_{ans}\) 则你得 \(100\) 分,否则你得 \(0.5\frac{\ln{m_{sum}}}{\ln{m_{ans}}}\) 分。

  这题出到这里可以结束了。但出题人为了验证你的 \(m\) 是算的还是蒙的,又给了 \(Q\) 次操作,每次操作中:

    交互库向第一个函数输入一个 \([0,m-1]\) 内 \(\text{long long}\) 类型的数,你可以用任意加密手段,将该数加密成一个 \(n\) 位 \(01\) 字符串并返回给交互库。

    然后交互库向第二个函数输入你刚才加密得到的密串,这个密串有可能被交互库恶搞,导致该串所有位取反,然后整个串翻转。你需要用适当的解密手段,将其解密为一开始向第一个函数输入的 \(\text{long long}\) 类型的数,并返回给交互库。

    每次操作后,交互库会判断第二个函数返回的数 是否和一开始向第一个函数输入的数一样。

  一旦有一次操作加密前的数和解密后的数不一样,你就得不到解密分数,即之前根据 \(m\) 得的分数打折 \(20\%\)。

  有防作弊机制(即开全局变量记录原数),详见原题面。

  subtask1 (30pts):\(n\le 18\)

  subtask2 (70pts):\(n\le 60\)

  对于所有数据,\(0\le Q\le 50000\)

  

  由于交互题描述很长,我懒得一字不差地搬完,下面放上完整题面,但问题描述写得有点恶心,我一开始没看懂





Solution

  设 \(k\) 是长度为 \(n\) 且被恶搞后不变的串的数目。

  先考虑 \(n\) 是奇数的情况。

  显然翻转之后正中间的一个 bit 一定会取反,此时 \(k=0,\space m=2^{n-1}\)。编码方式也很简单,让正中间的 bit 为 \(0\),解码时若正中间的 bit 为 \(1\) 则执行恶搞操作。

  然后是(我)想不到的 \(n\) 是偶数的情况。

  不难算出 \(k=2^{\frac{n}{2}}\),因为一个串被恶搞后与原串相同,当且仅当这个 \(01\) 串的第 \(1\) 位与第 \(n\) 位不同,第 \(2\) 位与第 \(n-1\) 位不同,第 \(3\) 位与第 \(n-2\) 为不同,以此类推,共 \(\frac{n}{2}\) 组对称位。这些被恶搞后不变的串互不混淆,都可以作为密串

  对于其余所有被恶搞后有变化的串,一定是两两配对,共 \(\frac{2^n-2^{\frac{n}{2}}}{2}\) 对。每一对中我们只能使用一个数作为加密后的串,因为一对中的 \(2\) 个都选的话,万一交互库把你加密后的串恶搞了,你就无法区分这两种密串,也就不知道应该用哪种密串解密出原数。

  那么在密串长度为 \(n\) 的限制下,共有 \(2^{\frac{n}{2}} + \frac{2^n-2^{\frac{n}{2}}}{2} = 2^{n-1} + 2^{\frac{n}{2}-1}\) 种互不混淆的密串。

  神奇操作:我们可以把 \([0,m-1]\) 种所有整数一一映射到这些密串,故 \(m=2^{n-1} + 2^{\frac{n}{2}-1}\)。

  那我们怎么构造一种映射方式呢?

  我们肯定得从密串中抠出 \(1\) 或 \(2\) 位,来标记这个串是否被恶搞,不然肯定没法做。

  而且为了固定这个标记位,即被恶搞后不会翻转到对称位(你的第 \(2\) 个程序无法判断收到的密串的标记位有没有被翻到对称位,因为你只能通过标记位判断密串有没有翻转),若抠出 \(1\) 位,那么串长 \(n\) 必须是奇数,而这里是偶数,舍。故我们要从密串中抠出 \(2\) 位,且这 \(2\) 位对称。

  抠哪里呢?

  这里一般就是盲猜结论了,大佬们都觉很简单……当然我可以写一个推法(?)

  把 \(m=2^{n-1} + 2^{\frac{n}{2}-1}\) 的值写成二进制数,发现只有 \(2\) 位为 \(1\),故该值也写成 \(2^{\frac{n}{2}} - \sum\limits_{k=1}^{n/2} 2^{n-k-1}\)

  \(2^{n-k-1}\) 可以拆成 \(2^{k-1} 2^{n-2k}\)

  观察一下这是什么?设抠掉了密串的第 \(k\) 位和第 \(n-k+1\) 位,\(k-1\) 表示的是密串前 \(k-1\) 位和后 \(k-1\) 位,\(n-2k\) 表示的是密串的第 \(k+1\) 位到第 \(n-k\) 位。那么,第 \(k\) 位和第 \(n-k+1\) 位就被空出来了!可以把这两位当作标记位!

  设 \(x\) 为满足密串第 \(x\) 位不等于第 \(n-x+1\) 位条件下的最小值,我们把所有密串按 \(x\) 从小到大分类。显然 \(x\) 的范围是 \([1,\frac{n}{2}+1]\),其中 \(x=\frac{n}{2}+1\) 的意义比较特殊,表示每一组对称位上的数都相同。

  由于前 \(x-1\) 组对称位上的数都相同,故给每一位放一个 \(0\) 或 \(1\),方案数为 \(2^{x-1}\);第 \(x+1\) 到 \(\frac{n}{2}\) 组对称位上的数没有要求,故给每一位放一个 \(0\) 或 \(1\),方案数为 \(2^{n-2x}\)。

  发现这种设标记位的方式 恰好可以映射 \(m\) 个数。于是我们可以据此构造映射方式了!

  映射方式很简单,我们把密串看成二进制数,自创一个二进制数比大小的规则,以确定 \(m\) 个用于映射的二进制数的排名,其排名 \(-1\) 就是映射到的 \([0,m-1]\) 中的原数。

  规则:以 \(x\) 从小到大为第一关键字,第 \(1\) 到 \(n-x+1\) 组成的二进制数从小到大为第二关键字。

  有了规则,设原数为 \(a\),则加密时求排第 \(a+1\) 名的密串,解密时求密串的排名 \(-1\) 即可。

#include<bits/stdc++.h>
#define ll long long
using namespace std; class Entropy
{
public:
int n;
ll getM(int _n)
{
n = _n;
if(n&1) return 1ll<<(n-1);
else return (1ll<<(n-1))|(1ll<<((n>>1)-1));
}
string getstr(char x) {string ret; ret=ret+(x==0?"0":"1"); return ret;}
string encode(ll x)
{
char str[65];
for(int i=0; i<n-1; i++) str[i] = (x&(1ll<<(n-2-i)))?1:0;
string ret;
if(n&1)
{
for(int i=0; i<((n-1)>>1); i++) ret = ret+getstr(str[i]);
ret = ret+"0";
for(int i=((n-1)>>1); i<n-1; i++) ret = ret+getstr(str[i]);
}
else
{
for(int i=0; i<=(n>>1); i++)
{
ll avail = i<(n>>1)?n-i-2:i,y = (1ll<<avail);
if(x<y)
{
for(int j=0; j<i; j++) {avail--; ret = ret+(x&(1ll<<avail)?"1":"0");}
if(i<(n>>1)) ret = ret+"0";
for(int j=i+1; avail; j++) {avail--; ret = ret+(x&(1ll<<avail)?"1":"0");}
if(i<(n>>1)) ret = ret+"0";
for(int j=i-1; j>=0; j--) {ret = ret+getstr((ret[j]-'0')^1);}
break;
}
x -= y;
}
}
return ret;
}
ll decode(string str)
{
char str0[65]; for(int i=0; i<n-1; i++) str0[i] = str[i]-'0';
ll ret = 0ll;
if(n&1)
{
if(str[n>>1]=='1')
{
for(int i=n-1; i>=0; i--)
{
if(i==(n>>1)) continue;
ret = (ret<<1)|(str[i]=='0'?1ll:0);
}
}
else
{
for(int i=0; i<n; i++)
{
if(i==(n>>1)) continue;
ret = (ret<<1)|(str[i]=='1'?1ll:0);
}
}
}
else
{
for(int i=0; i<=(n>>1); i++)
{
if(i==(n>>1) || str[i]==str[n-1-i])
{
ll tmp = 0ll;
if(str[i]=='0')
{
for(int j=0; j<i; j++) {tmp = (tmp<<1)|(str[j]=='1'?1:0);}
for(int j=i+1; j<n-i-1; j++) {tmp = (tmp<<1)|(str[j]=='1'?1:0);}
}
else
{
for(int j=n-1; j>n-i-1; j--) {tmp = (tmp<<1)|(str[j]=='0'?1:0);}
for(int j=n-i-2; j>i; j--) {tmp = (tmp<<1)|(str[j]=='0'?1:0);}
}
ret += tmp;
break;
}
ret += (1ll<<n-i-2);
}
}
return ret;
}
};
#include "entropy.h"

【安徽集训】Entropy的更多相关文章

  1. 【安徽集训】fiend

    考试的时候只会 \(O(Tn^3)\) 的做法,其它题还都不会,想到一整场就打这么点是人都能写的暴力没啥意思,就懒得写了.. Description 双人博弈.每一轮 A 和 B 同时选择一个 \(1 ...

  2. 【安徽集训】Emerald

    Description \(n\) 座城市在数轴上,第 \(i\) 座城市有一条连向第 \(i+1\) 座城市的单向边.每座城市有一个类型 A/B 以及一个非负整数人口,A 类城市的人觉得自己的城市比 ...

  3. [BZOJ2599][Race][IOI2011]点分治

    这是为了真正去学一下点分治..然后看了迪克李的ppt 又是一道写(改)了很久的题..终于ac了 1354799 orzliyicheng 2599 Accepted 31936 kb 23584 ms ...

  4. NOI2017 酱油记

    侥幸混进市队让我晚退役了几个月..不过终究还是退役了呢..这应该是最后一篇游记了吧.. 考前半个月都在安徽集训..然后发现所有人都停课集训..只有我暑假了开始.. 反正上课各种听不懂..各种被大佬虐. ...

  5. QDEZ集训笔记【更新中】

    这是一个绝妙的比喻,如果青岛二中的台阶上每级站一只平度一中的猫,差不多站满了吧 自己的理解 [2016-12-31] [主席树] http://www.cnblogs.com/candy99/p/61 ...

  6. 一个python的计算熵(entropy)的函数

    计算熵的函数: # -*- coding: utf-8 -*- import math #the function to calculate entropy, you should use the p ...

  7. Shannon entropy

    Shannon entropy is one of the most important metrics in information theory. Entropy measures the unc ...

  8. [转载] Calculating Entropy

    From:  johndcook.com/blog For a set of positive probabilities pi summing to 1, their entropy is defi ...

  9. paper 38 :entropy

    图像熵计算 真是为了一个简单的基础概念弄的心力交瘁,请教了一下师姐,但是并没有真的理解,师弟我太笨呀~~所以,我又查熵的中文含义和相关的出处!共勉吧~~ 1.信息熵: 利用信息论中信息熵概念,求出任意 ...

随机推荐

  1. mybatis 传递多个查询参数

    方法1:顺序传参法 public User selectUser(String name, int deptId); <select id="selectUser" resu ...

  2. kubeadm安装集群系列-4.证书更新

    证书更新 默认证书一年有效期 一旦证书过期,使用kubectl时会出现如下提示:`Unable to connect to the server: x509: certificate has expi ...

  3. 【VS开发】使用VS2010创建MFC ActiveX工程项目

    1.ActiveX的基本概念 ActiveX控件可以看作是一个极小的服务器应用程序,它不能独立运行,必须嵌入到某个容器程序中,与该容器一起运行.这个容器包括WEB网页,应用程序窗体等... Activ ...

  4. eclipse 如何从Gitee.com克隆工程到本地,并运行

    1.再项目资源管理器里选择导入,导入 2.在导入向导中选择Git,选择来自Git的项目 3.选克隆URL 4.输入URL 和用户密码,点击下一步 4.下一步 5.选择保存路径 6.选择下一步,自动导入 ...

  5. Sql 备忘——行号

    SELECT row_number() over(order by Product.ID) as [row_number]

  6. POJ 3207 【2-SAT入门题 + 强连通分量】

    这道题是我对于2-SAT问题的入门题:http://poj.org/problem?id=3207 一篇非常非常非常好的博客,很详细,认真看一遍差不多可以了解个大概:https://blog.csdn ...

  7. Tcpdump移植

    摘要: tcpdump对网络上的数据包进行截获的包分析工具. tcpdump可以将网络中传送的数据包的“头”完全截获下来提供分析.它支持针对网络层.协议.主机.网络或端口的过滤,并提供and.or.n ...

  8. Minimum Number of Arrows to Burst Balloons

    There are a number of spherical balloons spread in two-dimensional space. For each balloon, provided ...

  9. docker-配置网桥-自定义网络

    容器网络访问原理 桥接宿主机网络 临时生效: # 网桥名称 br_name=br0 # 添加网桥 brctl addbr $br_name # 给网桥设置IP ip addr add 192.168 ...

  10. 北电之死:谁谋杀了华为的对手?——银湖资本(Silver Lake)董事总经理爱德华·詹德出任CEO,既不了解华为,也不重视中国,直截了当地否决了收购华为

    作者:戴老板:微信公众号:饭统戴老板(ID: worldofboss) 2003年5月,北京SARS疫情紧张,摩托罗拉集团总裁迈克·扎菲罗夫斯基(Mike Zafirovski)却准备不走寻常路,决定 ...