洛谷 4106 / bzoj 3614 [HEOI2014]逻辑翻译——思路+类似FWT
题目:https://www.luogu.org/problemnew/show/P4106
https://www.lydsy.com/JudgeOnline/problem.php?id=3614
可以先把给出的东西排序成这样:
-1 -1 -1
-1 -1 1
-1 1 -1
-1 1 1
1 -1 -1
1 -1 1
1 1 -1
1 1 1
就是后面看成低位、前面看成高位,1看成1、-1看成0的二进制的顺序。
发现把第1行和第2行相加再除以2,得到的就是与 x3 无关的所有系数 a 在 x1 = -1 , x2 = -1 的情况下的值;
第2行减第1行再除以2,得到的就是与 x3 有关的所有系数 a 在 x3 = 1 , x1 = -1 , x2 = -1 的情况下的值;
把所有行两个一组相加的答案放在一起考虑,就是所有与 x3 无关的系数在 x1 , x2 取 -1 , -1 ; -1 , 1 ; 1 , -1 ; 1 , 1 的情况下的值;相减的话就是 x1 , x2 取各种值,x3的值都是1的情况;这就是一个子问题了。
所有把所有行两个一组相加除以2的值放在前半部分,两个一组相减(下面减上面)除以2的值放在后半部分,大概就能做了。
最后第1行就是和所有 x 都无关的那个 a ,也就是常数项;第2行仔细考虑一下,是 x1 的系数。即,算出来的值在第 i 行的就是取 x 方案为 i ( i 就像状压了取哪些x乘起来的那一项)的项的系数。排序输出即可。
注意分数中途爆 int 。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
using namespace std;
const int N=(<<)+,M=;
int n,bin[M],r[N]; char ch[M];
int gcd(int a,int b){return b?gcd(b,a%b):a;}
struct Node{
int x,y;
void yf()
{
if(!y||!x)return;
if(y<)y=-y,x=-x;
int g=gcd(x>?x:-x,y);x/=g;y/=g;
}
Node operator+ (const Node &b)const
{
Node c; c.y=(ll)y*b.y/gcd(y,b.y);
c.x=(ll)x*c.y/y+(ll)b.x*c.y/b.y;
c.yf(); return c;
}
Node operator- (const Node &b)const
{
Node u,v;u.x=x;u.y=y; v.x=b.x;v.y=-b.y;
return u+v;
}
}a[][N];
bool cmp(int a,int b)
{
for(int i=;i<n;i++)
{
if(!a)return true; if(!b)return false;
if((a&bin[i])&&(b&bin[i]))
{
a-=bin[i];b-=bin[i];continue;
}
if(!(a&bin[i])&&!(b&bin[i]))continue;
if(a&bin[i])return true; if(b&bin[i])return false;
}
}
void solve(int len)
{
for(int i=;i<len;i++)
if(i<r[i])swap(a[][i],a[][r[i]]);
for(int R=len,u=,v=;R>;R>>=,u=!u,v=!v)
{
int tot=-;//here
for(int i=;i<len;i+=R)
{
for(int j=;j<R;j+=)
{
a[u][++tot]=a[v][i+j]+a[v][i+j+];
a[u][tot].y*=; a[u][tot].yf();
}
for(int j=;j<R;j+=)
{
a[u][++tot]=a[v][i+j+]-a[v][i+j];
a[u][tot].y*=; a[u][tot].yf();
}
}
}
}
int main()
{
scanf("%d",&n);
bin[]=;for(int i=;i<=n;i++)bin[i]=bin[i-]<<;
for(int i=;i<bin[n];i++)r[i]=(r[i>>]>>)+((i&)?bin[n-]:);
for(int i=;i<bin[n];i++)
{
scanf("%s",ch);
long long d=;
for(int j=;j<n;j++)
d|=(ch[j]=='+'?bin[j]:);
double tmp; scanf("%lf",&tmp);
a[][d].x=(int)(tmp*+(tmp>?0.5:-0.5)); a[][d].y=;///round!
a[][d].yf();
}
solve(bin[n]);int fx=n&;
for(int i=;i<bin[n];i++)r[i]=i;
sort(r,r+bin[n],cmp);
for(int i=,u=r[];i<bin[n];i++,u=r[i])
if(a[fx][u].x)
{
printf("%d",a[fx][u].x);
if(a[fx][u].y>)printf("/%d",a[fx][u].y);
if(u)
{
putchar(' ');
for(int j=;j<n;j++)
if(u&bin[j])printf("x%d",j+);
}
puts("");
}
return ;
}
但这样空间在洛谷上能过, bzoj 上过不了。本来算下来就很大。
考虑不要把 a[ ] 开成滚动数组了。比如不要把两个一组相加的值放在前一半、相减的值放在后一半,而是把两行 i 和 i+1 相加的值放在第 i 行,相减的值放在第 i+1 行;这样就和 FWT 的模板长得更像,只开一个 a[ ] 而不用滚动也能应付过来。
考虑这样算了一次之后,下一次是哪里相加、相减。其实就相当于是原来的前一半,其间穿插上后一半的值;所以原来是前一半相邻两行再相加,现在就是隔一行相加;即原来是分治到前半部分和后半部分,现在是分治到奇数项和偶数项;这样下去就是 i 和 i+4 匹配、i 和 i+8 匹配……套上 FWT 的那个循环就行了。
仔细想一想,发现这样算出来,第1行是常数项,第2行是只和 x3 有关的项……也就是角标的二进制最低位是1表示有 x3 ,最高位是1表示有 x1 ……
如果一开始的排序是:
-1 -1 -1
1 -1 -1
-1 1 -1
1 1 -1
……
这样的话算出来的结果就是角标二进制最低位是1表示有x1……这样的。
输出可以写 dfs ,先搜这一位填1的,再搜这一位填0的;搜下一位之前输出一下,即每个方案在它填完最高位的1之后输出,如果是填了0就不输出,因为这个方案在最靠近的1被填了之后曾经输出过。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
using namespace std;
const int N=(<<)+,M=;
int n,bin[M]; char ch[M];
int gcd(int a,int b){return b?gcd(b,a%b):a;}
struct Node{
int x,y;
void yf()
{
if(!y||!x)return;
if(y<)y=-y,x=-x;
int g=gcd(x>?x:-x,y);x/=g;y/=g;
}
Node operator+ (const Node &b)const
{
Node c; c.y=(ll)y*b.y/gcd(y,b.y);//ll
c.x=(ll)x*c.y/y+(ll)b.x*c.y/b.y;
// return c;
c.yf(); return c;
}
Node operator- (const Node &b)const
{
Node u,v;u.x=x;u.y=y; v.x=b.x;v.y=-b.y;
return u+v;
}
void print(int id)
{
if(!x)return;
yf();
if(y>)printf("%d/%d",x,y);
else printf("%d",x);
if(id)
{
putchar(' ');
for(int i=;i<n;i++)
if(id&bin[i])printf("x%d",i+);
}
puts("");
}
}a[N];
void dfs(int cr,int ml)
{
if(!cr||ml&bin[cr-]) a[ml].print(ml);
if(cr==n)return;
dfs(cr+,ml|bin[cr]);
dfs(cr+,ml);
}
int main()
{
scanf("%d",&n); int len=(<<n);
bin[]=;for(int i=;i<=n;i++)bin[i]=bin[i-]<<;
for(int i=;i<len;i++)
{
scanf("%s",ch);
int d=;
for(int j=;j<n;j++)
d|=(ch[j]=='+'?bin[j]:);
double tmp; scanf("%lf",&tmp);
a[d].x=round(tmp*); a[d].y=;
a[d].yf();
}
for(int R=;R<=len;R<<=)
{
for(int i=,m=R>>;i<len;i+=R)
for(int j=;j<m;j++)
{
Node x=a[i+j],y=a[i+m+j];
a[i+j]=x+y; a[i+m+j]=y-x;
a[i+j].y*=; a[i+j].yf();
a[i+m+j].y*=; a[i+m+j].yf();
}
}
dfs(,);
return ;
}
洛谷 4106 / bzoj 3614 [HEOI2014]逻辑翻译——思路+类似FWT的更多相关文章
- 洛谷 P4106 / bzoj 3614 [ HEOI 2014 ] 逻辑翻译 —— 思路+递归
题目:https://www.luogu.org/problemnew/show/P4106 https://www.lydsy.com/JudgeOnline/problem.php?id=3614 ...
- 洛谷 P2827 BZOJ 4721 UOJ #264 蚯蚓
题目描述 本题中,我们将用符号表示对c向下取整,例如:. 蛐蛐国最近蚯蚓成灾了!隔壁跳蚤国的跳蚤也拿蚯蚓们没办法,蛐蛐国王只好去请神刀手来帮他们消灭蚯蚓. 蛐蛐国里现在共有n只蚯蚓(n为正整数).每只 ...
- 洛谷 P3307: bzoj 3202: [SDOI2013] 项链
题目传送门:洛谷P3307.这题在bzoj上是权限题. 题意简述: 这题分为两个部分: ① 有一些珠子,每个珠子可以看成一个无序三元组.三元组要满足三个数都在$1$到$m$之间,并且三个数互质,两个珠 ...
- 洛谷 P3332 BZOJ 3110 [ZJOI2013]K大数查询
题目链接 洛谷 bzoj 题解 整体二分 Code #include<bits/stdc++.h> #define LL long long #define RG register usi ...
- 洛谷 P2486 BZOJ 2243 [SDOI2011]染色
题目描述 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221” ...
- 洛谷 P2155 BZOJ 2186 codevs 2301 [SDOI2008]沙拉公主的困惑
题目描述 大富翁国因为通货膨胀,以及假钞泛滥,政府决定推出一项新的政策:现有钞票编号范围为1到N的阶乘,但是,政府只发行编号与M!互质的钞票.房地产第一大户沙拉公主决定预测一下大富翁国现在所有真钞票的 ...
- 洛谷 P2046 BZOJ 2007 海拔(NOI2010)
题目描述 YT市是一个规划良好的城市,城市被东西向和南北向的主干道划分为n×n个区域.简单起见,可以将YT市看作 一个正方形,每一个区域也可看作一个正方形.从而,YT城市中包括(n+1)×(n+1)个 ...
- 洛谷 P1903 BZOJ 2120 清橙 A1274【模板】分块/带修改莫队(数颜色)(周奕超)
试题来源 2011中国国家集训队命题答辩 题目描述 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会像你发布如下指令: 1. Q L R代表询问你从第L支画笔 ...
- 洛谷 P2709 BZOJ 3781 小B的询问
题目描述 小B有一个序列,包含N个1~K之间的整数.他一共有M个询问,每个询问给定一个区间[L..R],求$\sum_1^Kc_i^2$的值,其中$c_i$表示数字i在[L..R]中的重复次数.小B请 ...
随机推荐
- Linux系统下配置squid代理服务器的过程详解
简单记录一下Squid透明代理服务器的配置 环境:VirtualBox + CentOS 6.0 + squid-3.1.4-1.el6.i686 0.检查squid是否默认安装,没有安装的先安装 [ ...
- 《Maven实战》第10章 使用Maven进行测试
10.2maven-surefire-plugin插件 [生命周期]的[阶段]与[插件]的[目标]绑定 default生命周期的test阶段:使用单元测试框架运行测试 Maven内置绑定:defaul ...
- 防盗链&CSRF&API接口幂等性设计
防盗链技术 CSRF(模拟请求) 分析防止伪造Token请求攻击 互联网API接口幂等性设计 忘记密码漏洞分析 1.Http请求防盗链 什么是防盗链 比如A网站有一张图片,被B网站直接通过img标签属 ...
- GCD汇总
//总结如下: //1.同步请求:不会开启新的线程 //1-1.同步请求--串行队列:不开启新线程--按照顺序执行下去 //1-2.同步请求--并发列队:不开启新线程--按照顺序执行下去 //2.异步 ...
- Java编程时部分快捷键
alt + / 内容助理 配置:Window->properties->keys->查看alt + /的配置,然后解除当前的配置->搜索content assist->解 ...
- Sudoku Solver, 求数独
问题描述:填充数独表中空元素.空元素为'.' 算法分析:没填充一个数,都要看这个数所在的行,列,小矩阵是否合法.然后还要看整个数独表是否正确,而判断整个数独表只能通过递归,因为前一个结果的判断要依赖后 ...
- Oracle的导出和导入
(摘自:http://www.cnblogs.com/mchina/archive/2012/09/12/2678093.html) 数据库的备份操作是在整个项目运行中最重要的工作之一. 一.数据的导 ...
- 【ccf 2017/12/4】行车路线(dijkstra变形)
问题描述 小明和小芳出去乡村玩,小明负责开车,小芳来导航. 小芳将可能的道路分为大道和小道.大道比较好走,每走1公里小明会增加1的疲劳度.小道不好走,如果连续走小道,小明的疲劳值会快速增加,连续走s公 ...
- 条款5.了解c++默默编写并且调用了哪些函数。
如果想在一个内含reference成员的class内支持赋值操作,必须自己定义copy assignment操作符.而且面对“内含有const成员的”class,编译器的反应也是相同的,由于更改con ...
- 版本工具管理之----git
如何查看隐藏文件夹: 如果你看不到.git目录,你需要让隐藏的文件可见.具体做法就是打开一个Terminal窗口,输入以下命令: defaults write com.apple.finder App ...