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

UOJ

思路

很容易想到\(O(3^{3m}\log T)\)的暴力大矩乘,显然过不了。

我们分析一下每次转移的性质。题目给的转移方程是填表法,我们试着改成刷表法看看……

发现好像没啥用。

注意到游戏的规则是1吃0,2吃1,0吃2,也就是在\(x-y=1\pmod 3\)的时候\(x\)吃\(y\)。

我们枚举\(j\),然后再枚举\(i\ominus j\)(这里减法是每一位不退位减法),根据\(i\ominus j\)的状态来更新\(f_i\)。

换句话说,枚举\(j,k\),然后用\(f_j\times b_{cnt1[k],cnt2[k]}\)来更新\(f_{j\oplus k}\)。

发现这就是一个高维循环卷积的形式,用FWT来做。

由于模数的特殊性质,可以发现模数一定和3互质,所以最后是可以得到答案的。

(不太懂网上那么多题解为什么一定要强行分析转移矩阵的性质啊qwq)

代码

我一开始写得太丑了卡不过去,学习了minamoto神仙的代码之后才过。

#include<bits/stdc++.h>
clock_t t=clock();
namespace my_std{
    using namespace std;
    #define pii pair<int,int>
    #define fir first
    #define sec second
    #define MP make_pair
    #define rep(i,x,y) for (int i=(x);i<=(y);i++)
    #define drep(i,x,y) for (int i=(x);i>=(y);i--)
    #define go(x) for (int i=head[x];i;i=edge[i].nxt)
    #define templ template<typename T>
    #define sz 550000
    typedef long long ll;
    typedef double db;
    mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
    templ inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);}
    templ inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
    templ inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
    templ inline void read(T& t)
    {
        t=0;char f=0,ch=getchar();double d=0.1;
        while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
        while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
        if(ch=='.'){ch=getchar();while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();}
        t=(f?-t:t);
    }
    template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);}
    char __sr[1<<21],__z[20];int __C=-1,__zz=0;
    inline void Ot(){fwrite(__sr,1,__C+1,stdout),__C=-1;}
    inline void print(register int x)
    {
        if(__C>1<<20)Ot();if(x<0)__sr[++__C]='-',x=-x;
        while(__z[++__zz]=x%10+48,x/=10);
        while(__sr[++__C]=__z[__zz],--__zz);__sr[++__C]='\n';
    }
    void file()
    {
        #ifdef NTFOrz
        freopen("a.in","r",stdin);
        #endif
    }
    inline void chktime()
    {
        #ifndef ONLINE_JUDGE
        cout<<(clock()-t)/1000.0<<'\n';
        #endif
    }
//  inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std;

int n,m,T,mod;
ll b[15][15];

int add(int x,int y)
{
    int cur=1,ret=0;
    rep(k,1,m) ret+=(x+y)%3*cur,cur*=3,x/=3,y/=3;
    return ret;
}

struct hh{ll x,y;hh(ll X=0,ll Y=0){x=X,y=Y;}}f[sz],w[sz]; // x + y \times \omega
inline ll M1(ll x){return x-((mod-x-1)>>31&mod);}
inline ll M2(ll x){return x+(x>>31&mod);}
hh operator * (hh a,hh b) { return hh(M2(a.x*b.x%mod-a.y*b.y%mod),M2(M1(a.x*b.y%mod+a.y*b.x%mod)-a.y*b.y%mod)); }
hh operator + (hh a,hh b) { return hh(M1(a.x+b.x),M1(a.y+b.y)); }
bool operator < (hh a,hh b){return a.x==b.x?a.y<b.y:a.x<b.x;}
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;return ret;}
ll Ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x) if (y&1) ret=ret*x;return ret;}
hh kksm(hh x,int y){hh ret=hh(1,0);for (;y;y>>=1,x=x*x) if (y&1) ret=ret*x;return ret;}
void exgcd(ll a,ll b,ll &x,ll &y)
{
    if (a==1&&!b) return (void)(x=1,y=0);
    exgcd(b,a%b,y,x);y=M2(y-a/b*x%mod);
}
ll inv(ll x){ll a,b;exgcd(x,mod,a,b);return (a+mod)%mod;}

hh calc1(hh a){return hh(M2(-a.y),M2(a.x-a.y));}
hh calc2(hh a){return hh(M2(a.y-a.x),M2(-a.x));}
void FWT(hh *a,int type)
{
    for (int len=1,i=0;i<m;i++,len*=3) for (int j=0;j<n;j+=len*3) rep(k,0,len-1)
    {
        hh x=a[j+k],y=a[j+k+len],z=a[j+k+len*2],Y1=calc1(y),Y2=calc2(y),Z1=calc1(z),Z2=calc2(z);
        if (type==-1) swap(Y1,Y2),swap(Z1,Z2);
        a[j+k]=x+y+z;
        a[j+k+len]=x+Y1+Z2;
        a[j+k+len+len]=x+Y2+Z1;
    }
}

int main()
{
    file();
    read(m,T,mod);n=Ksm(3,m);
    if (mod==1) { rep(i,0,n-1) puts("0"); return 0; }
    rep(i,0,n-1) read(f[i].x);
    rep(i,1,m+1) rep(j,1,m+2-i) read(b[i-1][j-1]);
    rep(i,0,n-1)
    {
        int x=i,y=i,c1=0,c2=0;
        rep(k,1,m) c1+=(x%3==1),x/=3;
        rep(k,1,m) c2+=(y%3==2),y/=3;
        w[i].x=b[c1][c2];
    }
    FWT(w,1);FWT(f,1);
    map<hh,hh>M;
    rep(i,0,n-1) w[i]=(M.count(w[i])?M[w[i]]:M[w[i]]=kksm(w[i],T))*f[i];
    FWT(w,-1);
    ll I=inv(n);
    rep(i,0,n-1) printf("%lld\n",w[i].x*I%mod);
    return 0;
}

原文地址:https://www.cnblogs.com/p-b-p-b/p/11404257.html

时间: 2024-10-25 13:53:44

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

codeforces 1103E\清华集训 石家庄的工人阶级队伍比较坚强

希望复习高进制FWT的时候,能够快速回想起来. FWT感觉就是每一维单独考虑,(虽然我不知道为什么这是对的) 分别对一个奇怪的东西做DFT, 那个奇怪的东西在k进制下就是关于k次单位根的范德蒙特矩阵. 范德蒙特矩阵的逆矩阵大致就是每行除了第一个数之外翻转一下,然后除以矩阵的阶. 也可理解为原矩阵把k次单位根取反,反正每一维上就是个DFT,按FFT的做法搞就行了. 然后这两道题毒瘤的地方就在于不能用实数来表示一个复数,否则会爆精. 而且你也不一定可以算出单位根的值,十分毒瘤. 于是你就需要搞事,

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

传送门 设运算 \(op1,op2\),一个表示三进制不进位的加法,一个表示不退位的减法 设 \(cnt1[x],cnt2[x]\) 分别表示 \(x\) 转成三进制后 \(1/2\) 的个数 那么 \(f_{i,x}=\sum f_{i-1,y}b_{cnt1[x~op2~y],cnt2[x~op2~y]}\) 设 \(B_{x,y}=b_{cnt1[x~op2~y],cnt2[x~op2~y]}\) 那么可以发现 \(B_{x,y}=B_{x~op2~y,0}\) 那么我们要求的就是 \(f

【UOJ274】【清华集训2016】温暖会指引我们前行 LCT

[UOJ274][清华集训2016]温暖会指引我们前行 任务描述 虽然小R住的宿舍楼早已来了暖气,但是由于某些原因,宿舍楼中的某些窗户仍然开着(例如厕所的窗户),这就使得宿舍楼中有一些路上的温度还是很低. 小R的宿舍楼中有n个地点和一些路,一条路连接了两个地点,小R可以通过这条路从其中任意一个地点到达另外一个地点.但在刚开始,小R还不熟悉宿舍楼中的任何一条路,所以他会慢慢地发现这些路,他在发现一条路时还会知道这条路的温度和长度.每条路的温度都是互不相同的. 小R需要在宿舍楼中活动,每次他都需要从

bzoj 4736 /uoj274【清华集训2016】温暖会指引我们前行 lct

[清华集训2016]温暖会指引我们前行 统计 描述 提交 自定义测试 寒冬又一次肆虐了北国大地 无情的北风穿透了人们御寒的衣物 可怜虫们在冬夜中发出无助的哀嚎 “冻死宝宝了!” 这时 远处的天边出现了一位火焰之神 “我将赐予你们温暖和希望!” 只见他的身体中喷射出火焰之力 通过坚固的钢铁,传遍了千家万户 这时,只听见人们欢呼 “暖气来啦!” 任务描述 虽然小R住的宿舍楼早已来了暖气,但是由于某些原因,宿舍楼中的某些窗户仍然开着(例如厕所的窗户),这就使得宿舍楼中有一些路上的温度还是很低. 小R的

UOJ 274 【清华集训2016】温暖会指引我们前行 ——Link-Cut Tree

魔法森林高清重置, 只需要维护关于t的最大生成树,然后链上边权求和即可. 直接上LCT 调了将近2h 吃枣药丸 #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define F(i,j,k) for (int i=j;i<=k;++i) #define D(i,j,k) for (int i=j;i&g

[BZOJ4730][清华集训2016][UOJ266] Alice和Bob又在玩游戏

题意:俩智障又在玩游戏.规则如下: 给定n个点,m条无向边(m<=n-1),保证无环,对于每一个联通块,编号最小的为它们的根(也就是形成了一片这样的森林),每次可以选择一个点,将其本身与其祖先全部删除,不能操作者输.判断先手胜负. 题解:比较神的一道题. 我们现在要解决的问题是怎么求解一棵子树的SG值,首先把根删掉的情况考虑,这很好办,直接把子树的sg异或起来就好,关键是如果删除点在子树里怎么办. 这里用到了一个巧妙的东西,trie.怎么会用这个呢?因为删除子树里的节点就相当于是子树里这种对应的

【UOJ】#273. 【清华集训2016】你的生命已如风中残烛

题目链接:http://uoj.ac/problem/273 $${Ans=\frac{\prod _{i=1}^{m}i}{w-n+1}}$$ 1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<vector> 5 #include<cstdlib> 6 #include<cmath> 7 #include<cstring> 8

【20161203-20161208】清华集训2016滚粗记&amp;&amp;酱油记&amp;&amp;游记

先挖坑(这个blog怎么变成游记专用了--) #include <cstdio> using namespace std; int main(){ puts("转载请注明出处:http://www.cnblogs.com/wangyurzee7/"); puts("谢谢您的配合"); puts("by wangyurzee7"); return 0; }

UOJ268 [清华集训2016] 数据交互 【动态DP】【堆】【树链剖分】【线段树】

题目分析: 不难发现可以用动态DP做. 题目相当于是要我求一条路径,所有与路径有交的链的代价加入进去,要求代价最大. 我们把链的代价分成两个部分:一部分将代价加入$LCA$之中,用$g$数组保存:另一部分将代价加在整条链上,用$d$数组保存. 这时候我们可以发现,一条从$u$到$v$的路径的代价相当于是$d[LCA(u,v)]+\sum_{x \in edge(u,v)}g[x]$. 如果是静态的,可以用树形DP解决. 看过<神奇的子图>的同学都知道,叶子结点是从它的儿子中取两个最大的出来,所