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
#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;i0 ? 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;
}