UOJ272 [清华集训2016] 石家庄的工人阶级队伍比较坚强 【分治乘法】
题目分析:
首先不难注意到式子就是异或卷积,所以考虑用分治乘法推出优化方法。
我们把一个整体$f$拆成$f-,f\pm,f+$,然后另一个拆成$g-,g\pm,g+$.这样做的好处是能更清楚的分析问题。下面我们下宽油(大雾)。
发现三个部分要求的式子是在两者相乘中选不同的三个,所以我们发现三个部分中每取一个有相同。这样我们聚焦到$--,-\pm,-+$三个东西。观察二进制FWT,可以假想它们要使用到三次单位根。这样只需要把三个根错开排列就行了。
做分治乘法的时候注意把虚部的$I$记做$\sqrt{3}i$.
代码:
#include<bits/stdc++.h>
using namespace std; const int maxn = ; struct cn{int rl,vir;}e[]; // vir's real meaning is vir*sqrt(3) int iv2,iv3;
int m,n,t,p,phi;
int b3[],b[][];
cn val[maxn],f[maxn]; int W[maxn],L[maxn]; cn operator +(const cn& alpha,const cn& beta){
cn ans = (cn){alpha.rl+beta.rl,alpha.vir+beta.vir};
if(ans.rl >= p) ans.rl -= p;
if(ans.vir >= p) ans.vir -= p;
return ans;
}
cn operator *(const cn& alpha,const cn& beta){
cn ans = (cn){,};
ans.rl = (1ll*alpha.rl*beta.rl-3ll*alpha.vir*beta.vir)%p;
ans.rl += p; if(ans.rl >= p) ans.rl -= p;
ans.vir = (1ll*alpha.vir*beta.rl+1ll*alpha.rl*beta.vir)%p;
return ans;
}
cn operator *(const cn& alpha,const int& beta){
cn ans=alpha;ans.rl=(1ll*ans.rl*beta)%p;ans.vir=(1ll*ans.vir*beta)%p;
return ans;
} cn fast_pow(cn now,int pw){
int bit = ;cn ans = (cn){,},dt = now;
while(bit <= pw){
if(bit & pw) ans = ans*dt;
bit<<=;dt = dt*dt;
}
return ans;
}
int fast_pow(int now,int pw){
int bit = ,ans = ,dt = now;
while(bit <= pw){
if(bit & pw) ans = (1ll*ans*dt)%p;
bit<<=;dt = (1ll*dt*dt)%p;
}
return ans;
} void read(){
scanf("%d%d%d",&m,&t,&p);
b3[] = ; for(int i=;i<=m;i++) b3[i] = b3[i-]*;
n = b3[m];
for(int i=;i<n;i++) scanf("%d",&f[i].rl);
for(int i=;i<=m;i++){
for(int j=;i+j<=m;j++){
scanf("%d",&b[i][j]);
}
}
val[].rl = b[][];
for(int i=;i<n;i++){
W[i] = W[i/],L[i] = L[i/];
if(i % == ) L[i]++;
if(i % == ) W[i]++;
val[i].rl = b[W[i]][L[i]];
}
} void multi(int l,int r){
if(l == r-){
f[l] = f[l]*fast_pow(val[l],t);
}else{
int l1 = l+(r-l)/,l2 = l+*(r-l)/,d = l2-l1;
for(int i=;i<d;i++){
cn p1 = f[l+i],p2 = f[l1+i],p3 = f[l2+i];
f[l+i] = p1+p2+p3;
f[l1+i] = p1+e[]*p2+e[]*p3;f[l2+i] = p1+e[]*p2+e[]*p3;
p1 = val[l+i],p2 = val[l1+i],p3 = val[l2+i];
val[l+i] = p1+p2+p3;
val[l1+i] = p1+e[]*p2+e[]*p3;val[l2+i] = p1+e[]*p2+e[]*p3;
}
multi(l,l1); multi(l1,l2); multi(l2,r);
for(int i=;i<d;i++){
cn p1 = f[l+i],p2 = f[l1+i],p3 = f[l2+i];
f[l+i] = p1+p2+p3;
f[l1+i] = p1+e[]*p2+e[]*p3;f[l2+i] = p1+e[]*p2+e[]*p3;
f[l+i]=f[l+i]*iv3;f[l1+i]=f[l1+i]*iv3;f[l2+i]=f[l2+i]*iv3;
}
}
} void init(){
phi = p;int z = p;
for(int i=;i*i<=p;i++){
if(p % i == ){
while(p%i == ) p /= i;
phi = (phi/i)*(i-);
}
}
if(p != ) phi = (phi/p)*(p-); p =z;
iv2 = fast_pow(,phi-); iv3 = fast_pow(,phi-);
e[] = (cn){,}; e[] = (cn){p-iv2,iv2}; e[] = (cn){p-iv2,p-iv2};
} void work(){
multi(,n);//[0,n)
for(int i=;i<n;i++) printf("%d\n",f[i].rl);
} int main(){
read();
init();
work();
return ;
}
UOJ272 [清华集训2016] 石家庄的工人阶级队伍比较坚强 【分治乘法】的更多相关文章
- [清华集训2016]石家庄的工人阶级队伍比较坚强——三进制FWT
题目链接: [清华集训2016]石家庄的工人阶级队伍比较坚强 题目大意:有$n=3^m$个人玩石头剪刀布,共$t$轮游戏,每轮每个人要和包括自己的所有人各进行$m$次石头剪刀布.每个人在$m$轮中的决 ...
- UOJ272. 【清华集训2016】石家庄的工人阶级队伍比较坚强 [FWT]
UOJ 思路 很容易想到\(O(3^{3m}\log T)\)的暴力大矩乘,显然过不了. 我们分析一下每次转移的性质.题目给的转移方程是填表法,我们试着改成刷表法看看-- 发现好像没啥用. 注意到游戏 ...
- uoj#272. 【清华集训2016】石家庄的工人阶级队伍比较坚强
http://uoj.ac/problem/272 这题的式子形式是异或卷积的三进制推广,因此可以设计一个类似fwt的变换,这里需要一个三次单位根$w$,满足$w^3\%p==1$且$(1+w+w^2 ...
- [uoj272]石家庄的工人阶级队伍比较坚强
假设$x,y\in \{0,1,2\}$,则$x$能赢$y$(根据题中定义)当且仅当$x-y\equiv 1(mod\ 3)$ 定义$\ominus$为两数3进制下不退位的减法,$S_{x}$表示$x ...
- uoj#276. 【清华集训2016】汽水(分数规划+点分治)
传送门 没想到点分治那一层-- 首先不难发现这是个分数规划,先把所有的边长减去\(k\),二分答案,设为\(mid\),就是要求路径平均值\(ans\in[-mid,mid]\) 先来考虑\(ans\ ...
- 【UOJ276】【清华集训2016】汽水(分数规划+点分治)
点此看题面 大致题意: 给你一棵树,要求你选择一条树上路径,使得这条路径上边权的平均值与定值\(k\)的差的绝对值最小.求出这个最小值. 分数规划 看到平均值,首先就应该想到分数规划吧. 我们二分答案 ...
- UOJ #274. 【清华集训2016】温暖会指引我们前行 [lct]
#274. [清华集训2016]温暖会指引我们前行 题意比较巧妙 裸lct维护最大生成树 #include <iostream> #include <cstdio> #incl ...
- UOJ_274_[清华集训2016]温暖会指引我们前行_LCT
UOJ_274_[清华集训2016]温暖会指引我们前行_LCT 任务描述:http://uoj.ac/problem/274 本题中的字典序不同在于空串的字典序最大. 并且题中要求排序后字典序最大. ...
- UOJ 275. 【清华集训2016】组合数问题
UOJ 275. [清华集训2016]组合数问题 组合数 $C_n^m $表示的是从 \(n\) 个物品中选出 \(m\) 个物品的方案数.举个例子,从$ (1,2,3)(1,2,3)$ 三个物品中选 ...
随机推荐
- Win10 Anaconda下TensorFlow-GPU环境搭建详细教程(包含CUDA+cuDNN安装过程)
目录 前言 第一步:安装Anaconda 1.下载和安装 2.配置Anaconda环境变量 第二步:安装TensorFlow-GPU 1.创建conda环境 2.激活环境 3.安装tensorflow ...
- LeetCode 595. Big Countries
There is a table World +-----------------+------------+------------+--------------+---------------+ ...
- React 与 React Native 底层共识:React 是什么
此系列文章将整合我的 React 视频教程与 React Native 书籍中的精华部分,给大家介绍 React 与 React Native 结合学习的方法,此小节主要介绍 React 的底层原理与 ...
- 第八次oo作业
作业五 作业五是当前最后一次电梯作业,也是我们第一次接触到多线程编程,输入方式也由之前的一次性输入变为了实时输入,其中涉及到大量的同步和冲突,其中学习多线程的使用也花了大量的时间,但总的来说为以后的作 ...
- i++ 相比 ++i 哪个更高效?为什么?
++i的效率高些,++i在运算过程中不产生临时对象,返回的就是i,是个左值,类似++i=1这样的表达式是合法的,而i++在运算的过程中会产生临时对象,返回的是零时对象的值,是个右值,像i++=1这样的 ...
- Verilog语法遗漏点
1 关于参数定义 Parameter:parameter只能定义在端口生命的前面,如 Input[whith:0] a; Parameter whith=4; 这样的参数定义出现在声明的后面会报错 2 ...
- Vue向后端请求课程展示
1.Vue结构 App.vue <template> <div id="app"> <router-link to="/index" ...
- semantic-ui 图标
semantic-ui提供了很多的图标,基本常用的在官网上面都能找到.要想记住这么多图标是不可能的,但是也是有简便方法记忆. 首先,图标其实和按钮的区别基本没有,要说有的话,也就是基础样式的大小不同吧 ...
- mysql 查看版本
查看mysql版本的四种方法 - 风生水起 - 博客园 http://www.cnblogs.com/end/archive/2011/10/18/2216461.html 查看mysql数据库版本方 ...
- # 【Python3练习题 007】 有一对兔子,从出生后第3个月起每个月都生一对兔子, # 小兔子长到第三个月后每个月又生一对兔子, # 假如兔子都不死,问每个月的兔子总数为多少?
# 有一对兔子,从出生后第3个月起每个月都生一对兔子,# 小兔子长到第三个月后每个月又生一对兔子, # 假如兔子都不死,问每个月的兔子总数为多少?这题反正我自己是算不出来.网上说是经典的“斐波纳契数列 ...