zoukankan      html  css  js  c++  java
  • P4106 [HEOI2014]逻辑翻译

    题目链接

    题意分析

    这道题就是上来一个多项式

    [f(x_1,x_2,x_3)=a_0+a_1x_1+a_2x_2+a_3x_3+a_4x_1x_2+a_5x_1x_3+a_6x_2x_3+a_7x_1x_2x_3 ]

    然后通过对于(x_1,x_2,x_3)不同的取值对应的函数值让我们得到这个多项式的系数

    首先 你可以暴力高斯消元 复杂度优美到飞起

    其实对于这道题的话 如果你们有FFT或者FWT的经验的话 这道题的思路应该是比较应该是比较好想的反正本蒟蒻是没有

    上述多项式转化一下

    [f(x_1,x_2,x_3)=a_0+a_2x_2+a_3x_3+a_6x_2x_3+x_1(a_1+a_4x_2+a_5x_3+a_7x_2x_3) ]

    然后的话 我们就可以分治了 但是对于左右应该怎么分治?

    我们考虑一下 对于(x_1)存在(1)以及(-1)两种取值

    那么取值不同的话就是(A)以及(B)

    然后我们可以是左半部分(frac{A+B}{2}) 右半部分(frac{A-B}{2})

    左半部分就是计算(x_2,x_3,x_2x_3)的系数以及常数项

    右半部分就是计算(x_1,x_1x_2,x_1x_3,x_1x_2x_3)的系数

    这大概就是答题的思路

    然后就是这道题一些比较有意思坑人的地方

    1.由于这道题的答案都是使用分数的形式输出 所以我们需要维护一个结构体进行分数运算

    2.这道题的输出比较呛人 所以我们考虑直接dfs输出

    3.一开始对于小数x的话 由于ta最多不超过2位小数 所以我们可以转化为分子round(100x) 分母(x) (round()函数是四舍五入的意思)

    具体的实现我们还是看代码实现

    CODE:

    #include<bits/stdc++.h>
    #define N 22
    #define M 1508611
    using namespace std;
    char s[N];
    long long gcd(long long x,long long y){return y ? gcd(y,x%y):x;}
    struct Node
    {//我用于维护分数的结构体
    	long long up,dow;//分子分母如果不使用long long的话中间结果会炸
    	friend Node operator +(const Node &A,const Node &B)
    	{
    		Node tmp;long long x;
    		tmp.up=A.up*B.dow+A.dow*B.up;
    		tmp.dow=A.dow*B.dow;
    		x=gcd((tmp.up>0 ? tmp.up:-tmp.up),(tmp.dow>0 ? tmp.dow:-tmp.dow));
    		if(tmp.dow<0) tmp.dow=-tmp.dow,tmp.up=-tmp.up;
    		return (Node){tmp.up/x,tmp.dow/x};
    	}
    	friend Node operator -(const Node &A,const Node &B)
    	{
    		Node tmp;long long  x;
    		tmp.up=A.up*B.dow-A.dow*B.up;
    		tmp.dow=A.dow*B.dow;
    		x=gcd((tmp.up>0 ? tmp.up:-tmp.up),(tmp.dow>0 ? tmp.dow:-tmp.dow));
    		if(tmp.dow<0) tmp.dow=-tmp.dow,tmp.up=-tmp.up;
    		return (Node){tmp.up/x,tmp.dow/x};
    	}
    	friend Node operator /(const Node &A,int B)
    	{
    		Node tmp;long long  x;
    		tmp.up=A.up;tmp.dow=A.dow*B;
    		x=gcd((tmp.up>0 ? tmp.up:-tmp.up),(tmp.dow>0 ? tmp.dow:-tmp.dow));
    		if(tmp.dow<0) tmp.dow=-tmp.dow,tmp.up=-tmp.up;
    		return (Node){tmp.up/x,tmp.dow/x};
    	}
    }num[M];
    int n;
    bool vis[M];
    void print(int now)
    {
    	if(vis[now]||num[now].up==0) return;
    	//这里为了防止重复输出 我使用了一个标记数组
    	//同时分子为0的话 就是本身值为0 那么就不用输出了 
    	vis[now]=1;
    	Node x=num[now];
    	if(x.dow==1) printf("%lld ",x.up);
    	else printf("%lld/%lld ",x.up,x.dow);
    	for(int i=0;i<n;++i)
    	if(now&(1<<i)) printf("x%d",i+1);
    	puts("");
    }
    void dfs_ans(int tox,int nowhave)
    {//我们是从低位到高位递归 对应的就是1,2,3,...,n 
    //nowhave就是当前枚举的位
    //tox就是已经枚举了的低位状态
    	if(nowhave==n) return;
    	for(int i=0;i<(1<<(n-nowhave-1));++i)
    	{//所以当前就是在枚举高位的状态   
    		int cdy=(i<<(nowhave+1))|(tox)|(1<<nowhave);//高位的状态|已经枚举了的低位状态|当前位是0还是1
    		int wzy=(i<<(nowhave+1))|(tox);
    		Node tmp=num[cdy];
    //这里的话我一直都不太好理解 后来才稍稍有些眉目
    //我们还是考虑一下 对于题目给出的2^n个状态 其他条件分别取了x1=1以及x1=-1时对应的函数值对应着什么 
    		num[cdy]=(tmp-num[wzy])/2;
    		num[wzy]=(tmp+num[wzy])/2;
    //我们按照上面的做法 消掉之后
    //就是等于当前这一位取0时(x2,x3,x2x3,常数项) 不同状态对应的不同函数值
    //以及当前这一位取1时(x1,x1x2,x1x3,x1x2x3) 不同状态对应的不同函数值
    //最后也就是相当于是axi+C 也就是a+C以及-a+C 从而得到我们要的答案
    	}
    	dfs_ans(tox,nowhave+1);
    	dfs_ans(tox|(1<<nowhave),nowhave+1);
    //然后我们分别用取和不取对应的状态 向高位前进
    }
    void print_ans(int tox,int nowhave)
    {
    	if(nowhave==n)
    	{//最后到了的话就是直接输出
    		print(tox);
    		return;
    	} 
    	print(tox);//当前这一位没有的话自然是字典序优先级最高的 所以我们优先输出
    	print_ans((tox|(1<<nowhave)),nowhave+1);//然后的话就是低位先有低位优先
    	print_ans(tox,nowhave+1);
    }
    int main()
    {
    	scanf("%d",&n);
    	for(int i=0;i<(1<<n);++i)
    	{
    		int now=0;double tmp;
    		scanf("%s %lf",s,&tmp);
    		for(int j=0;j<n;++j)
    		if(s[j]=='+') now+=(1<<j); 
    		//首先 一开始的读入我们直接转化为对应的二进制状态
    		num[now].up=round(tmp*100.0);
    		num[now].dow=100;
    		int x=gcd((num[now].up>0 ? num[now].up:-num[now].up),(num[now].dow>0 ? num[now].dow:-num[now].dow));
    		if(num[now].dow<0) num[now].up=-num[now].up,num[now].dow=-num[now].dow;
    		num[now].up/=x;num[now].dow/=x;
    		//然后是对于每一种状态对应函数值从小数维护成分数
    	}
    	dfs_ans(0,0);	
    	print_ans(0,0);
    	return 0;
    } 
    
  • 相关阅读:
    python 基础2.5 循环中continue与breake用法
    python 基础 2.4 while 循环
    python 基础 2.3 for 循环
    python 基础 2.2 if流程控制(二)
    python 基础 2.1 if 流程控制(一)
    python 基础 1.6 python 帮助信息及数据类型间相互转换
    python 基础 1.5 python数据类型(四)--字典常用方法示例
    Tornado Web 框架
    LinkCode 第k个排列
    LeetCode 46. Permutations
  • 原文地址:https://www.cnblogs.com/LovToLZX/p/14100482.html
Copyright © 2011-2022 走看看