您的位置:首页 > 其它

各种模板总结

2016-09-26 13:10 246 查看
数据结构

线段树

树链剖分 √

Treap

Splay

左偏堆

划分树 待添加

字符串

KMP

MANACHER

字典树

01字典树 √

AC自动机 √

后缀数组 √

回文树 √

数论

矩阵快速幂 待添加

图论

最短路(Dijkastra)待添加

最短路(Floyd)待添加

最短路(SPFA)待添加

最小生成树(Prim) 待添加

最小生成树(Kurskal) 待添加

计算几何

扫描线 √

其他

大整数模板 √

快速输入模板 (整数) √

快速输入模板 (实数) √

1~MOD的逆元 √

-

树链剖分

const int maxn = 100000 + 5;        //树中节点个数

//边集
struct Edge{
int v,pre,c;
}Es[maxn * 2];
int head[maxn],TOT_EDGE;
void INIT_EDGE(){                   //边集初始化
memset(head,-1,sizeof head);
TOT_EDGE = 0;
}
void ADD_EDGE(int u,int v,int c){   //添加边
Es[TOT_EDGE].v = v;
Es[TOT_EDGE].c = c;
Es[TOT_EDGE].pre = head[u];
head[u] = TOT_EDGE++;
}

/**树链剖分部分*/
/**
**  son:    节点重儿子
**  fa:     节点父节点
**  dep:    节点在树中深度
**  size:   节点子树的大小
**  top:    节点在重链中的深度最低节点(最高节点)
**  tid:    节点编号(hash值)
**  RANK:   RANK[v]编号为v的是第RANK[v]节点
**  SegSize:用于编号的迭代辅助变量,最小编号为SegSize的初始值
*/
int son[maxn],fa[maxn],dep[maxn],size[maxn];
int top[maxn],tid[maxn],RANK[maxn],SegSize;
int DFS(int rt){
dep[rt] = dep[fa[rt]] + 1;
son[rt] = 0;
size[rt] = 1;
for(int i = head[rt];~i;i = Es[i].pre){
int v = Es[i].v;
if(v != fa[rt]){
fa[v] = rt;
size[rt] += DFS(v);
if(size[son[rt]] < size[v]) son[rt] = v;
}
}
return size[rt];
}
void Split(int rt,int tp){
top[rt] = tp;
tid[rt] = ++SegSize;
RANK[tid[rt]] = rt;
if(son[rt]){
Split(son[rt],tp);
for(int i = head[rt];~i;i = Es[i].pre){
int v = Es[i].v;
if(v != fa[rt] && v != son[rt]) Split(v,v);
}
}
}
void TreeLineSplit(){       //开始剖分
dep[0] = 0;
size[0] = 0;
fa[1] = 0;
DFS(1);
SegSize = -1;
Split(1,1);
}


Treap

/**
**  ch:节点的孩子节点
**  fa:夫节点
**  fix;优先级
**  size:当前子树的大小
**  tot:节点个数(包括sroot)
**  sroot:超级根节点
**  key:节点的键值
*/
const int maxn = 15000 + 50,INF = 0x7fffffff;
int ch[maxn][2],fa[maxn],fix[maxn],size[maxn];
int tot,root,sroot;
int key[maxn];

/**
**  Treap初始化
*/
void Treap_Init(){
tot = 1;
root = sroot = 0;
ch[sroot][0] = ch[sroot][1] = 0;
fa[sroot] = 0;
size[sroot] = 0;
fix[sroot] = key[sroot] = INF;
}

/**
**  新建一个父节点为FA,键值为k的节点,返回节点编号
**
*/
int NewNode(int FA,int k){
ch[tot][0] = ch[tot][1] = 0;
fa[tot] = FA;
size[tot] = 1;
fix[tot] = rand();
key[tot] = k;
return tot++;
}

/**
**  更新rt的size信息
*/
void PushUp(int rt){ size[rt] = size[ch[rt][0]] + size[ch[rt][1]] + 1; if(rt == sroot) size[rt] = 0;}

/**
**  旋转操作
**  kind:   0.表示rt为fa[rt]的左孩子 进行右旋操作 zig
**  kind:   1.表示rt为fa[rt]的右孩子 进行左旋操作 zag
*/
void rotate(int rt,int kind){
int prt = fa[rt];
ch[prt][kind] = ch[rt][!kind];fa[ch[rt][!kind]] = prt;
ch[fa[prt]][ch[fa[prt]][1] == prt] = rt;fa[rt] = fa[prt];
ch[rt][!kind] = prt;fa[prt] = rt;
PushUp(prt);PushUp(rt);
}

/**
**  在根为rt的树中插入键值为K的元素 这里可以重复键值
*/
void Insert(int rt,int k){
while(ch[rt][k >= key[rt]]) rt = ch[rt][k >= key[rt]];
ch[rt][k >= key[rt]] = NewNode(rt,k);
rt = ch[rt][k >= key[rt]];
while(fa[rt] != sroot && fix[rt] > fix[fa[rt]]) rotate(rt,ch[fa[rt]][1] == rt);
if(fa[rt] == sroot) root = rt;
while(fa[rt] != sroot){
rt = fa[rt];PushUp(rt);
}
}

/**
**  删除键值为k的节点,使用前要保证一定有键值为k的节点
*/
void Delete(int rt,int k){
if(key[rt] == k){
if(ch[rt][0] && ch[rt][1]){
int nrt = ch[rt][0];
if(fix[nrt] < fix[ch[rt][1]]) nrt = ch[rt][1];
rotate(nrt,ch[rt][1] == nrt);
Delete(rt,k);PushUp(nrt);
}
else{
int nrt = ch[rt][0];
if(nrt == sroot) nrt = ch[rt][1];
ch[fa[rt]][ch[fa[rt]][1] == rt] = nrt;fa[nrt] = fa[rt];
}
}
else{
Delete(ch[rt][k >= key[rt]],k);
PushUp(rt);
}
}

/**
**  在rt的树中查找键值第k小的节点 返回节点编号
*/
int Search(int rt,int k){
if(k <= size[ch[rt][0]]) return Search(ch[rt][0],k);
else if(k > size[ch[rt][0]] + 1) return Search(ch[rt][1],k - 1 - size[ch[rt][0]]);
else return rt;
}

/**
**  查找键值为k的节点在树中是第几小的
*/
int getRank(int rt,int k){
if(rt == sroot) return 0;
if(k >= key[rt]) return size[ch[rt][0]] + 1 + getRank(ch[rt][1],k);
else return getRank(ch[rt][0],k);
}


Splay

/** ---- SPLAY ---- **/
/**  ch     边
**  fa     父节点
**  size   子树大小
**  key    关键字大小
**  tot    总共节点的个数
**  root   当前的树根
**  sroot  超级根节点
**/
int ch[maxn][2],fa[maxn],size[maxn];
int key[maxn],pos[maxn];
int tot,root,sroot;

/** 初始化 */
void Splay_Init(){
tot = 1;
root = sroot = 0;
ch[0][0] = ch[0][1] = 0;
fa[0] = 0;
key[0] = INF;
size[0] = 0;
}

/** 新建一个节点 */
int NewNode(int FA,int k,int p){
ch[tot][0] = ch[tot][1] = 0;
fa[tot] = FA;
size[tot] = 1;
key[tot] = k,pos[tot] = p;
return tot++;
}

/** 更新当前子树的大小 和 根节点保留的信息 */
void PushUp(int rt){size[rt] = 1 + size[ch[rt][0]] + size[ch[rt][1]];}

/** 节点的旋转操作
**  kind 0 表示rt为fa[rt]的左孩子
**  kind 1 表示rt为fa[rt]的右孩子
**  kind 0 进行zig 1 进行zag
*/
void rotate(int rt,int kind){
int prt = fa[rt];
ch[prt][kind] = ch[rt][!kind];fa[ch[rt][!kind]] = prt;
ch[fa[prt]][ch[fa[prt]][1] == prt] = rt;fa[rt] = fa[prt];
ch[rt][!kind] = prt;fa[prt] = rt;
PushUp(prt);PushUp(rt);
}

/** 将rt节点 伸展至goal的孩子节点 */
void Splay(int rt,int goal){
while(fa[rt] != goal){
if(fa[fa[rt]] == goal) rotate(rt,ch[fa[rt]][1] == rt);
else{
int prt = fa[rt],kind = (ch[fa[prt]][1] == prt);
if(ch[prt][kind] == rt) rotate(rt,kind),rotate(rt,kind);
else rotate(rt,!kind),rotate(rt,kind);
}
}
if(fa[rt] == sroot) root = rt;
}

/** 在根为rt的树内,插入关键字为k的节点 */
void Insert(int rt,int k,int p){
while(ch[rt][k > key[rt]]) rt = ch[rt][k > key[rt]];
rt = (ch[rt][k > key[rt]] = NewNode(rt,k,p));
Splay(rt,sroot);
}

/** 在根为rt的树内,查找关键字为k的节点 */
int Find(int rt,int k){
while(ch[rt][k >= key[rt]])
if(k == key[rt]) return rt;
else rt = ch[rt][k >= key[rt]];
return sroot;
}

/** 查找关键字为k 的前驱 */
int Find_Pre(int rt,int k){
rt = Find(rt,k);
Splay(rt,sroot);
if(ch[rt][0] == sroot) return sroot;
else rt = ch[rt][0];
while(ch[rt][1]) rt = ch[rt][1];
return rt;
}

/** 查找关键字为k 的后继 */
int Find_Next(int rt,int k){
rt = Find(rt,k);
Splay(rt,sroot);
if(ch[rt][1] == sroot) return sroot;
else rt = ch[rt][1];
while(ch[rt][0]) rt = ch[rt][0];
return rt;
}


01字典树

const int maxn = 100000 + 5;        //集合中的数字个数
typedef long long LL;
int ch[32 * maxn][2];               //节点的边信息
LL value[32 * maxn];                //节点存储的值
int node_cnt;                       //树中当前节点个数

inline void init(){                 //树清空
node_cnt = 1;
memset(ch[0],0,sizeof(ch));
}

inline void Insert(LL x){           //在字典树中插入 X
//和一般字典树的操作相同 将X的二进制插入到字典树中
int cur = 0;
for(int i = 32;i >= 0;--i){
int idx = (x >> i) & 1;
if(!ch[cur][idx]){
memset(ch[node_cnt],0,sizeof(ch[node_cnt]));
ch[cur][idx] = node_cnt;
value[node_cnt++] = 0;
}
cur = ch[cur][idx];
}
value[cur] = x;             //最后的节点插入value
}

inline LL Query(LL x){              //在字典树中查找和X异或的最大值的元素Y 返回Y的值
int cur = 0;
for(int i = 32;i >= 0;--i){
int idx = (x >> i) & 1;
if(ch[cur][idx ^ 1]) cur = ch[cur][idx ^ 1];
else cur = ch[cur][idx];
}
return value[cur];
}


KMP

const int maxn = 100;
char s[maxn],p[maxn];
int fail[maxn];
/*  p为模式串
**  f为保存失配边的数组
**
*/
void getFail(char* p,int* f){
int m = strlen(p);
f[0] = 0; f[1] = 0;
for(int i = 1;i < m;++i){
int j = f[i];
while(j && p[i] != p[j]) j = f[j];
f[i + 1] = p[i] == p[j] ? j + 1 : 0;
}
}
/*
**  s为文本串 p为模式串,fail保存失配边
**  匹配成功返回true
**  失败返回false
*/
bool Match(char* s,char* p,int* fail){
getFail(p,fail);//得到fail数值
int m = strlen(p),n = strlen(s);
int i = 0, j = 0;
while(i < n){
while(i < n && j < m && s[i] == s[j]){//新一轮匹配
i++,j++;
}
if(j == m) return true;//匹配成功
j--;
while(j && p[j] != s[i]) j = fail[j];//根据fail跳转
}
return false;
}


AC自动机

const int maxn = 10000 * 50 + 50,sigma_size = 26;

/** AC_AUTOMATON */
int ch[maxn][sigma_size],fail[maxn],tot;
int value[maxn];

/** 初始化 */
void Init(){
memset(ch[0],0,sizeof ch[0]);
tot = 1;
fail[0] = -1;value[0] = 0;
}

/** 插入字符串 s */
void Insert(char* s){
int idx,cur = 0;
while( *s ){
idx = *s - 'a';
if(ch[cur][idx] == 0){
memset(ch[tot],0,sizeof ch[tot]);
fail[tot] = 0;
value[tot] = 0;
ch[cur][idx] = tot++;
}
cur = ch[cur][idx];
s++;
}
value[cur]++;
}

/** GetFail */
void GetFail(){
queue<int> Q;
Q.push(0);
fail[0] = -1;
int cur,idx,f;
while(!Q.empty()){
cur = Q.front();Q.pop();
for(int i = 0;i < sigma_size;++i){
if(ch[cur][i]){
f = fail[cur];
while(f != -1 && ch[f][i] == 0) f = fail[f];
fail[ch[cur][i]] = (f == -1) ? 0 : ch[f][i];
Q.push(ch[cur][i]);
}
else{
f = fail[cur];
ch[cur][i] = (f == -1) ? 0 : ch[f][i];
}
}
}
}
/**  以上具有通用性 */
/** 匹配 */
int Search(char *s){
int cur = 0,idx,ret = 0,tmp;
while(*s){
idx = *s - 'a';
tmp = cur = ch[cur][idx];
if(value[tmp]) while(tmp){
ret += value[tmp];value[tmp] = 0;
tmp = fail[tmp];
}
s++;
}
return ret;
}


MANACHER

const int maxn = 500;
int dis[maxn];
char str1[maxn],str2[maxn];

int get_dis(){
int len = strlen(str1);
str2[0] = '$';
char* str_a = str2 + 1;
for(int i = 0;i <= len;++i){
str_a[i * 2] = '#';
str_a[i * 2 + 1] = str1[i];
}
int id = 0, mx = 1,len2 = strlen(str2);
for(int i = 1;i < len2;++i){
if(mx > i){
dis[i] = (dis[id * 2 - i] < (mx - i) ? dis[2 * id - i] : (mx - i));
}
else dis[i] = 1;
while(str2[i - dis[i]] == str2[i + dis[i]]) dis[i]++;
if(i + dis[i] > mx){
mx = i + dis[i];
id = i;
}
}
return len2;
}


后缀数组

int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
int cmp(int *r,int a,int b,int l)
{return r[a]==r&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m)
{
int i,j,p,*x=wa,*y=wb,*t;

for(i=0;i<m;i++) ws[i]=0;
for(i=0;i<n;i++) ws[x[i]=r[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[x[i]]]=i;
for(j=1,p=1;p<n;j*=2,m=p)
{

for(p=0,i=n-j;i<n;i++) y[p++]=i;
for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;

for(i=0;i<n;i++) wv[i]=x[y[i]];

for(i=0;i<m;i++) ws[i]=0;
for(i=0;i<n;i++) ws[wv[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i];
for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
return;
}
int rank[maxn],height[maxn];
void calheight(int *r,int *sa,int n)
{
int i,j,k=0;
for(i=1;i<=n;i++) rank[sa[i]]=i;
for(i=0;i<n;height[rank[i++]]=k)
for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
return;
}


[b]回文树


const int MAXN = 100005;

struct node {
int next[26];   //边
int len;        //回文串长度
int sufflink;   //后缀指针
int num;
};

int len;
char s[MAXN];
node tree[MAXN];
int num;            // node 1 - root with len -1, node 2 - root with len 0
int suff;           // max suffix palindrome
long long ans;

bool addLetter(int pos) {

int cur = suff, curlen = 0;
int let = s[pos] - 'a';

while (true) {
curlen = tree[cur].len;                                     //当前可能上一个回文串长度
if (pos - 1 - curlen >= 0 && s[pos - 1 - curlen] == s[pos]) //如果能形成行如XAX的回文串
break;
cur = tree[cur].sufflink;                                   //查找失败 找到更小的回文
}
if (tree[cur].next[let]) {                                      //这个节点已经存在
suff = tree[cur].next[let];                                 //更新最长前缀值
return false;
}

num++;
suff = num;
tree[num].len = tree[cur].len + 2;
tree[cur].next[let] = num;              //加一个节点

if (tree[num].len == 1) {               //只有一个X
tree[num].sufflink = 2;             //指向空串
tree[num].num = 1;
return true;
}

while (true) {
cur = tree[cur].sufflink;
curlen = tree[cur].len;
if (pos - 1 - curlen >= 0 && s[pos - 1 - curlen] == s[pos]) {
tree[num].sufflink = tree[cur].next[let];
break;
}
}
tree[num].num = 1 + tree[tree[num].sufflink].num;
return true;
}

void initTree() {
num = 2; suff = 2;
tree[1].len = -1; tree[1].sufflink = 1;
tree[2].len = 0; tree[2].sufflink = 1;
}


字典树

struct Trie{
/**
*   maxnode:    Trie树中最多可能的节点个数 上限为字符串个数 * 最长长度
*   sigma_size: 组成字符串的字符种类
*   ch:         边
*   value:      节点的值
*   sz:         Trie树的总节点个数
*/
int ch[maxnode][sigma_size];
int value[maxnode];
int sz;
int IDX(char c) {return c - 'a';}
Trie(){
sz = 1;
memset(ch[0],0,sizeof(ch[0]));
}

/**
*  字符串s插入Trie中 值为V
*/
void Insert(char* s,int v){
int u = 0,len = strlen(s);
for(int i = 0;i < len;++i){
int c = IDX(s[i]);
if(!ch[u][c]){
memset(ch[sz],0,sizeof(ch[sz]));
value[sz] = 0;
ch[u][c] = sz++;
}
u = ch[u][c];
}
value[u] = v;
}

/**
*   查找字符串s 返回v
*/
int Search(char* s){
int cur = 0,idx;
while(*s){
idx = IDX(*s);
if(ch[cur][idx] == 0) return -1;
cur = ch[cur][idx];
s++;
}
return value[cur];
}
};


线段树

#include <bits/stdc++.h>
using namespace std;

/** 线段树模板 */
/** 以求区间和为例 */
#define lson rt << 1 , l ,mid
#define rson rt << 1 | 1,mid + 1,r
const int maxn = 50000 + 50;
int v[maxn << 2],laze[maxn << 2];
int A[maxn];

// 向下Push laze标记
void PushDown(int rt,int l,int r){
if(laze[rt]){
int mid = l + r >> 1,lcnt = mid - l + 1,rcnt = r - mid;
v[rt << 1] = v[rt << 1] + lcnt * laze[rt];
v[rt << 1 | 1] = v[rt << 1 | 1] + rcnt * laze[rt];
laze[rt << 1] += laze[rt];laze[rt << 1 | 1] += laze[rt];
laze[rt] = 0;
}
}
//向上更新sum值
void PushUp(int rt){
v[rt] = v[rt << 1] + v[rt << 1 | 1];
}
void Build(int rt,int l,int r){
if(l == r){
v[rt] = A[l];return;
}
int mid = l + r >> 1;
Build(lson),Build(rson);
laze[rt] = 0;
PushUp(rt);
}

//将区间L,R 增加X
void Update(int rt,int l,int r,int L,int R,int x){
if(L <= l && R >= r){
v[rt] += x * (r - l + 1);
laze[rt] += x;
return;
}
PushDown(rt,l,r);
int mid = l + r >> 1;
if(L <= mid) Update(lson,L,R,x);
if(R > mid) Update(rson,L,R,x);
PushUp(rt);
}

int Query(int rt,int l,int r,int L,int R){
if(L <= l && R >= r){
return v[rt];
}
PushDown(rt,l,r);
int mid = l + r >> 1;
int ret = 0;
if(L <= mid) ret += Query(lson,L,R);
if(R > mid) ret += Query(rson,L,R);
PushUp(rt);
return ret;
}


左偏堆

int key[maxn],dis[maxn],ch[maxn][2];
/**合并以a,b为堆顶的堆*/
int Merge(int a,int b){
if(!a) return b;if(!b) return a;
if(key[a] < key) swap(a,b);
ch[a][1] = Merge(ch[a][1],b);
if(dis[ch[a][0]] < dis[ch[a][1]]) swap( ch[a][0],ch[a][1] );
if(ch[a][1] == 0) dis[a] = 0;
else dis[a] = dis[ch[a][1]] + 1;
return a;
}


[b]大整数


struct BigInteger{
int A[25];
enum{MOD = 10000};
BigInteger(){memset(A, 0, sizeof(A)); A[0]=1;}
void set(int x){memset(A, 0, sizeof(A)); A[0]=1; A[1]=x;}
void print(){
printf("%d", A[A[0]]);
for (int i=A[0]-1; i>0; i--){
if (A[i]==0){printf("0000"); continue;}
for (int k=10; k*A[i]<MOD; k*=10) printf("0");
printf("%d", A[i]);
}
printf("\n");
}
int& operator [] (int p) {return A[p];}
const int& operator [] (int p) const {return A[p];}
BigInteger operator + (const BigInteger& B){
BigInteger C;
C[0]=max(A[0], B[0]);
for (int i=1; i<=C[0]; i++)
C[i]+=A[i]+B[i], C[i+1]+=C[i]/MOD, C[i]%=MOD;
if (C[C[0]+1] > 0) C[0]++;
return C;
}
BigInteger operator * (const BigInteger& B){
BigInteger C;
C[0]=A[0]+B[0];
for (int i=1; i<=A[0]; i++)
for (int j=1; j<=B[0]; j++){
C[i+j-1]+=A[i]*B[j], C[i+j]+=C[i+j-1]/MOD, C[i+j-1]%=MOD;
}
if (C[C[0]] == 0) C[0]--;
return C;
}
};


快速输入 (整数)

inline bool scan_d(int &num)
{
char in;bool IsN=false;
in=getchar();
if(in==EOF) return false;
while(in!='-'&&(in<'0'||in>'9')) in=getchar();
if(in=='-'){ IsN=true;num=0;}
else num=in-'0';
while(in=getchar(),in>='0'&&in<='9'){
num*=10,num+=in-'0';
}
if(IsN) num=-num;
return true;
}


快速输入 (实数)

inline bool scan_lf(double &num)
{
char in;double Dec=0.1;
bool IsN=false,IsD=false;
in=getchar();
if(in==EOF) return false;
while(in!='-'&&in!='.'&&(in<'0'||in>'9'))
in=getchar();
if(in=='-'){IsN=true;num=0;}
else if(in=='.'){IsD=true;num=0;}
else num=in-'0';
if(!IsD){
while(in=getchar(),in>='0'&&in<='9'){
num*=10;num+=in-'0';}
}
if(in!='.'){
if(IsN) num=-num;
return true;
}else{
while(in=getchar(),in>='0'&&in<='9'){
num+=Dec*(in-'0');Dec*=0.1;
}
}
if(IsN) num=-num;
return true;
}


扫描线 √

using namespace std;
const int maxn = 100 + 5;
const int TOT_SEG = maxn * 2;
/** Seg
**  l,r,h 分别为线段的左端点,右端点,高
**  f 标识上下边
*/
struct Seg{
int f;
double l,r,h;
void set(double ll,double rr,double hh,int d){
l = ll,r = rr,h = hh,f = d;
}
}Segs[TOT_SEG];
bool cmp(const Seg& a,const Seg& b){
return a.h < b.h;
}
double AR[TOT_SEG]; /** 区间长度 */
map<double,int> POS; /** 将端点 HASH 到区间上 */
int FALG[TOT_SEG]; /** 区间被覆盖的次数 */
int Seg_CNT,HASH_SEG_CNT;
void SEG_HASH(){
POS.clear();HASH_SEG_CNT = 2;
sort(Segs + 1,Segs + Seg_CNT,cmp);
sort(AR + 1,AR + Seg_CNT);
for(int i = 2;i < Seg_CNT;++i){
if(AR[i] != AR[i - 1]){
AR[HASH_SEG_CNT] = AR[i];
POS[AR[i]] = HASH_SEG_CNT++;
}
}
for(int i = 1;i < HASH_SEG_CNT;++i){
AR[i] = AR[i + 1] - AR[i];
}
}


1~MOD的逆元 √

#define mod 9973ll
typedef long long LL;
LL inv[mod];
inv[1] = 1;
for(int i = 2;i < mod;++i) inv[i] = (mod - mod / i) * (inv[mod % i]) % mod;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: