题目分析:

首先不难注意到式子就是异或卷积,所以考虑用分治乘法推出优化方法。
我们把一个整体$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] 石家庄的工人阶级队伍比较坚强 【分治乘法】的更多相关文章

  1. [清华集训2016]石家庄的工人阶级队伍比较坚强——三进制FWT

    题目链接: [清华集训2016]石家庄的工人阶级队伍比较坚强 题目大意:有$n=3^m$个人玩石头剪刀布,共$t$轮游戏,每轮每个人要和包括自己的所有人各进行$m$次石头剪刀布.每个人在$m$轮中的决 ...

  2. UOJ272. 【清华集训2016】石家庄的工人阶级队伍比较坚强 [FWT]

    UOJ 思路 很容易想到\(O(3^{3m}\log T)\)的暴力大矩乘,显然过不了. 我们分析一下每次转移的性质.题目给的转移方程是填表法,我们试着改成刷表法看看-- 发现好像没啥用. 注意到游戏 ...

  3. uoj#272. 【清华集训2016】石家庄的工人阶级队伍比较坚强

    http://uoj.ac/problem/272 这题的式子形式是异或卷积的三进制推广,因此可以设计一个类似fwt的变换,这里需要一个三次单位根$w$,满足$w^3\%p==1$且$(1+w+w^2 ...

  4. [uoj272]石家庄的工人阶级队伍比较坚强

    假设$x,y\in \{0,1,2\}$,则$x$能赢$y$(根据题中定义)当且仅当$x-y\equiv 1(mod\ 3)$ 定义$\ominus$为两数3进制下不退位的减法,$S_{x}$表示$x ...

  5. uoj#276. 【清华集训2016】汽水(分数规划+点分治)

    传送门 没想到点分治那一层-- 首先不难发现这是个分数规划,先把所有的边长减去\(k\),二分答案,设为\(mid\),就是要求路径平均值\(ans\in[-mid,mid]\) 先来考虑\(ans\ ...

  6. 【UOJ276】【清华集训2016】汽水(分数规划+点分治)

    点此看题面 大致题意: 给你一棵树,要求你选择一条树上路径,使得这条路径上边权的平均值与定值\(k\)的差的绝对值最小.求出这个最小值. 分数规划 看到平均值,首先就应该想到分数规划吧. 我们二分答案 ...

  7. UOJ #274. 【清华集训2016】温暖会指引我们前行 [lct]

    #274. [清华集训2016]温暖会指引我们前行 题意比较巧妙 裸lct维护最大生成树 #include <iostream> #include <cstdio> #incl ...

  8. UOJ_274_[清华集训2016]温暖会指引我们前行_LCT

    UOJ_274_[清华集训2016]温暖会指引我们前行_LCT 任务描述:http://uoj.ac/problem/274 本题中的字典序不同在于空串的字典序最大. 并且题中要求排序后字典序最大. ...

  9. UOJ 275. 【清华集训2016】组合数问题

    UOJ 275. [清华集训2016]组合数问题 组合数 $C_n^m $表示的是从 \(n\) 个物品中选出 \(m\) 个物品的方案数.举个例子,从$ (1,2,3)(1,2,3)$ 三个物品中选 ...

随机推荐

  1. H3C交换机-SNMP配置

    1.1     SNMP基础配置 1.启动/关闭SNMP Agent服务 在系统视图模式下: 启用:snmp-agent 关闭:undo snmp-agent 注:缺省情况下snmp agent是关闭 ...

  2. nginx负载均衡精简配置实例

    [root@localhost ~]# vim nginx.conf user nginx; worker_processes ; error_log /var/log/nginx/error.log ...

  3. 二十一、当锚点遇到fixed(margin和padding)

    当锚点点击跳转的时候,如果上方有fixed,锚点跳转会默认跳转到top为0的地方,有一部分就被遮挡了 解决方法:(像素值随便给的) 给锚点跳转到的具体内容加padding-top:-50px:marg ...

  4. react 项目搭建

    1.首先运行环境-node是必须的,需要下载安装node的运行环境: 2.安装好了node之后,自然的就有了npm: 3.npm install -g creact-react-app/全局安装cre ...

  5. 关于always块内for循环的执行方式

    //该模块主要用来说明for结构在时序逻辑中的执行方式 :] eq_dly ); integer i; 'b1; always @(posedge clk_1 or negedge nrst) beg ...

  6. 周末时间学习Linux

    大家都是如何度过周末时光的呢?好多人都认为一周的工作后要好好休息下,于是在家疯狂的补觉,刷剧,打游戏,自我觉得很是正常,工作几天了,休息下不是当然嘛.是的,休息下很正常,但是把周末的时光都用到这些东西 ...

  7. Tea Party CodeForces - 808C (构造+贪心)

    Polycarp invited all his friends to the tea party to celebrate the holiday. He has ncups, one for ea ...

  8. python中换行,'\r','\n'及'、'\r\n'

    '\r'的本意是回到行首,'\n'的本意是换行. 所以回车相当于做的是'\r\n'或者'\n\r'.'\r'就是换行并回行首, '\n'就是换行并回行首,用'\r\n'表示换行并回行首. window ...

  9. Jmeter之上传数据流(图片、文本等)请求

    MIME类型~Content-Type: 参数名称~name

  10. CodeIgniter框架通过URL向控制器传递参数

    通过URL传递参数的方法是GET,在CodeIgnter框架中,通过URL有两种方式向控制器传递参数: 一种是键值对的形式. 一种是类似于文件路径的形式,这个时候,不是以键值对的形式了,我们只传递值. ...