(乱搞艹爆正解系列)

对不起,由于博主太弱了,并不会正解的多项式exp(甚至多项式exp我都不会2333)。

只能来说一说我是怎么乱搞的啦QWQ

首先这个题最关键的性质是: 一个在原置换 g 中长度为 l 的环,在 f 中会被拆成 gcd(l,n) 个 长度为 l/gcd(l,n) 的环  [可以类比同余系中的一些变换]

所以知道了这个,我们怎么反着搞回去呢???

先 O(N) 找出所有循环的长度,然后记 num[i] 为 f 中长度为i的环有多少个。这个时候,我们再知道了 哪些长度一样的环被合并到了一起,就可以计算出答案了。

因为长度不一样的环之间互不影响,所以我们可以把每个长度的环的答案乘起来,就是最终答案了(如果f中没有长度为i的环,那么这个长度的环的答案是1)。

于是我们就可以先从1到n扫一遍,把每个 i 存到 i/gcd(i,n) 的 vector 中去,表示 gcd(i,n) 个 i/gcd(i,n) 可以合并成一个 长度为i的环。

然后对于每个长度,我们只需要扫它的倍数dp即可,复杂度O(玄学)。

(至于中间怎么推dp的式子就不说了,就是一些组合数学的基本功练习2333)

为什么是 O(玄学)呢?

单纯的扫一遍倍数已经是 O(N * log (N))了,但是因为很多地方可以不用扫(比如没出现的环长,或者一种环长的环的长度和很小,不需要用到很大的dp数组),仔细算一下,扫的过程其实是 O(图中环的个数) 的,已经是低于线性的了。

但是可能一个vector里面会有很多元素啊,这样dp的时候会不会炸啊???

就比如 i=1 的时候,我们可能要扫 1~n中所有数的dp数组,再乘一个 vector 的大小,难道不是秒变 O(N^2)了吗?

但可以发现此时vector中的元素只有 n 的约数(请自行yy为什么),1e5以下的约数最多的到100吗(不太清楚)??

所以就算用心卡我,也很难卡掉吧QWQ

(达成目标 : 在代码量是标程 1/3的情况下 速度 比标程快了8倍  2333)

  1. #include<bits/stdc++.h>
  2. #define ll long long
  3. using namespace std;
  4. #define pb push_back
  5. const int maxn=100005,ha=998244353;
  6. inline int add(int x,int y){ x+=y; return x>=ha?x-ha:x;}
  7. inline void ADD(int &x,int y){ x+=y; if(x>=ha) x-=ha;}
  8. inline int ksm(int x,int y){
  9. int an=1;
  10. for(;y;y>>=1,x=x*(ll)x%ha) if(y&1) an=an*(ll)x%ha;
  11. return an;
  12. }
  13.  
  14. vector<int> g[maxn],w[maxn];
  15. int n,a[maxn],num[maxn],ans=1;
  16. int jc[maxn],ni[maxn],f[maxn];
  17. bool v[maxn];
  18.  
  19. int gcd(int x,int y){ return y?gcd(y,x%y):x;}
  20.  
  21. inline int P(int x,int y){ return jc[x]*(ll)ni[x-y]%ha;}
  22.  
  23. inline int work(int x){
  24. int an=0;
  25. while(!v[x]) an++,v[x]=1,x=a[x];
  26. return an;
  27. }
  28.  
  29. inline void solve(){
  30. jc[0]=1;
  31. for(int i=1;i<=n;i++) jc[i]=jc[i-1]*(ll)i%ha;
  32. ni[n]=ksm(jc[n],ha-2);
  33. for(int i=n;i;i--) ni[i-1]=ni[i]*(ll)i%ha;
  34.  
  35. for(int i=1;i<=n;i++) if(!v[i]) num[work(i)]++;
  36.  
  37. for(int i=n;i;i--) g[i/gcd(i,n)].pb(i);
  38.  
  39. for(int i=1;i<=n;i++)
  40. for(int j=0;j<g[i].size();j++) w[i].pb(ksm(i,g[i][j]/i-1));
  41.  
  42. for(int i=1;i<=n;i++) if(num[i]){
  43. int T=num[i]*i,now;
  44. f[0]=1;
  45.  
  46. for(int j=i;j<=T;j+=i){
  47. f[j]=0;
  48. for(int l=g[i].size()-1;l>=0;l--){
  49. now=g[i][l];
  50. if(now>j) break;
  51.  
  52. ADD(f[j],f[j-now]*(ll)P(j/i-1,now/i-1)%ha*(ll)w[i][l]%ha);
  53. }
  54. }
  55.  
  56. ans=ans*(ll)f[T]%ha;
  57. // cout<<f[T]<<endl;
  58. }
  59. }
  60.  
  61. int main(){
  62. // freopen("data.in","r",stdin);
  63. // freopen("data.out","w",stdout);
  64.  
  65. scanf("%d",&n);
  66. for(int i=1;i<=n;i++) scanf("%d",a+i);
  67.  
  68. solve();
  69.  
  70. printf("%d\n",ans);
  71. return 0;
  72. }

  

洛谷 - Sdchr 的邀请赛 T4 信息传递的更多相关文章

  1. 洛谷 - Sdchr 的邀请赛 T1 取石子

    比赛的时候都推出来了和 质因子的指数和有关,硬是没做出来QWQ,我傻死算了 但其实这是一个结论题,因为这本来就是阶梯NIM游戏的模型.阶梯NIM游戏是指,有 n+1 阶台阶(0 ~ n),每阶上都有若 ...

  2. 洛谷大宁的邀请赛~元旦祭F: U17264 photo(线段树)

    标程的写法稍微有点麻烦,其实不需要平衡树也是可以做的. 线段树上维护从左端点开始最远的有拍照的长度,以及区间的最大值. 考虑两段区间合并的时候,显然左区间必须取,右区间的第一个比左区间最大值大的数开始 ...

  3. 洛谷 1062 NOIP2006普及T4 数列

    [题解] 鲜活的水题..我们把数列换成k进制的,发现数列是001,010,011,100,101,110,111...,而第m项用k进制表示的01串刚好就是m的二进制的01串.于是我们预处理k的幂,把 ...

  4. [洛谷P3982]龙盘雪峰信息解析器

    题目大意:给你一串代码,要求进行解码.解码规则详见题目. 解题思路:这是一道字符串处理的题目. 首先,有这么几种情况输出Error: 1.代码中出现除了0和1外的字符. 2.代码长度不是8的倍数. 3 ...

  5. 洛谷P2661 信息传递(最小环,并查集)

    洛谷P2661 信息传递 最小环求解采用并查集求最小环. 只适用于本题的情况.对于新加可以使得两个子树合并的边,总有其中一点为其中一棵子树的根. 复杂度 \(O(n)\) . #include< ...

  6. tg2015 信息传递 (洛谷p2661)

    题目描述 有n个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学. 游戏开始时,每人都只知道自己的生日.之后每一 ...

  7. [NOIP2015] 提高组 洛谷P2661 信息传递

    题目描述 有n个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学. 游戏开始时,每人都只知道自己的生日.之后每一 ...

  8. 洛谷 P2661 信息传递 Label:并查集||强联通分量

    题目描述 有n个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学. 游戏开始时,每人都只知道自己的生日.之后每一 ...

  9. AC日记——信息传递 洛谷 P2661 (tarjan求环)

    题目描述 有n个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学. 游戏开始时,每人都只知道自己的生日.之后每一 ...

随机推荐

  1. bzoj2827: 千山鸟飞绝 平衡树 替罪羊树 蜜汁标记

    这道题首先可以看出坐标没有什么意义离散掉就好了. 然后你就会发现你要每次都更改坐标,而一旦更改受影响的是坐标里的所有数,要是一个一个的改,会不可描述. 所以换个视角,我们要找的是某只鸟所到每个坐标时遇 ...

  2. 线程 packaged_task future

    http://www.cnblogs.com/haippy/p/3279565.html #include <iostream> // std::cout #include <fut ...

  3. word公式编辑中的转义字符

    Some of the commonly used symbols:      \infty - Infinity      \leq - Less then or equal      \geq - ...

  4. HDU 多校对抗 F Naive Operations

    Naive Operations Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 502768/502768 K (Java/Other ...

  5. 对比append插入数据产生的redo量

    --版本信息 SELECT * FROM v$version; Oracle - Prod PL - Production CORE Production TNS - Production NLSRT ...

  6. Java拷贝构造函数初尝试

    浅复制(浅克隆) :被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象. 深复制(深克隆) :被复制 ...

  7. Round 0: Regionals 2010 :: NEERC Eastern Subregional

    Round 0: Regionals 2010 :: NEERC Eastern Subregional 贴吧题解(官方)? 网上的题解 水 A Murphy's Law 题意:Anka拿着一块涂着黄 ...

  8. [BZOJ1602&BZOJ1787&BZOJ2144]树上LCA的算法巩固练习

    简述求LCA的倍增算法 对于树上的所有节点,我们可以很轻松地通过dfs求出其直接的父亲节点以及其深度 通过类似RMQ的原理我们可以处理出每个节点的第2^i个父亲 //这个过程既可以在dfs之后双重循环 ...

  9. python基础===pip安装模块失败

    此情况只用于网络不畅的安装模块背景: 总出现红色的 Could not find a version that satisfies the requirement pymongo(from versi ...

  10. js 各种取整方式及方法

    1.直接丢弃小数部分,保留整数部分 a:parseInt(1.5555) b: 0|1.5555 2.向上取整 a: Math.ceil(1.5555) b: (1.5555+0.5).toFixed ...