tarjan求有向图强联通分量,缩点
1 //有向图求强联通分量,缩点 2 int head[110000],nex[110000],to[110000],tot; 3 int dfn[110000],low[110000],st[110000],inst[110000],belong[110000],num,cnt; 4 vector<int>vcc[110000]; 5 void tarjan(int x,int pre){ 6 dfn[x]=low[x]=++num; 7 st[++st[0]]=x,inst[x]=1; 8 for(register int i=head[x];i;i=nex[i]){ 9 int y=to[i]; 10 if(y==pre) continue; 11 if(!dfn[y]){ 12 tarjan(y,x); 13 low[x]=min(low[x],low[y]); 14 } 15 else if(inst[y]) low[x]=min(low[x],dfn[y]); 16 } 17 if(low[x]==dfn[x]){ 18 ++cnt;int y; 19 do{ 20 y=st[st[0]--]; 21 inst[y]=0; 22 belong[y]=cnt; 23 vcc.push_back(y); 24 }while(y!=x); 25 } 26 }
高精度板子
1 struct Big{ 2 int len,s[110000]; 3 Big(){memset(s,0,sizeof(s)),len=1;} 4 Big(register int val){*this=val;} 5 Big(const char *val){*this=val;} 6 Big operator = (const int &val){ 7 char s[110000]; 8 sprintf(s,"%d",val); 9 *this=s;return *this; 10 } 11 Big operator = (const char *val){ 12 len=strlen(val); 13 while(len>1&&val[0]=='0') ++val,len--; 14 for(register int i=0;i<len;++i) s[i]=val[len-i-1]-'0'; 15 return *this; 16 } 17 inline void deal(){ 18 while(len>1&&!s[len-1]) len--; 19 } 20 Big operator + (const Big &a)const{ 21 Big res;res.len=0; 22 int top=max(len,a.len),add=0; 23 for(register int i=0;add||i<top;++i){ 24 int now=add; 25 if(i<len) now+=s[i]; 26 if(i<a.len) now+=a.s[i]; 27 res.s[res.len++]=now%10; 28 add=now/10; 29 } 30 return res; 31 } 32 Big operator - (const Big &a)const{ 33 Big res;res.len=0;int del=0; 34 for(register int i=0;i<len;++i){ 35 int now=s[i]-del; 36 if(i<a.len) now-=a.s[i]; 37 if(now>=0) del=0; 38 else del=1,now+=10; 39 res.s[res.len++]=now; 40 } 41 res.deal();return res; 42 } 43 Big operator * (const Big &a)const{ 44 Big res;res.len=len+a.len; 45 for(register int i=0;i<len;i++) 46 for(register int j=0;j<a.len;j++) 47 res.s[i+j]+=s[i]*a.s[j]; 48 for(register int i=0;i<res.len;i++) 49 res.s[i+1]+=res.s[i]/10,res.s[i]%=10; 50 res.deal();return res; 51 } 52 Big operator / (const Big &a)const{ 53 Big res,cur=0;res.len=len; 54 for(register int i=len-1;~i;i--){ 55 cur=cur*Big(10),cur.s[0]=s[i]; 56 while(cur>=a) cur-=a,res.s[i]++; 57 } 58 res.deal();return res; 59 } 60 Big operator % (const Big &a)const{ 61 Big res=*this/a; 62 return *this-res*a; 63 } 64 Big operator += (const Big &a){ *this=*this+a; return *this;} 65 Big operator -= (const Big &a){ *this=*this-a; return *this;} 66 Big operator *= (const Big &a){ *this=*this*a; return *this;} 67 Big operator /= (const Big &a){ *this=*this/a; return *this;} 68 Big operator %= (const Big &a){ *this=*this%a; return *this;} 69 bool operator < (const Big &a)const{ 70 if(len!=a.len) return len<a.len; 71 for(register int i=len-1;~i;i--) 72 if(s[i]!=a.s[i]) return s[i]<a.s[i]; 73 return 0; 74 } 75 bool operator > (const Big &a)const{return a<*this;} 76 bool operator <= (const Big &a)const{return !(*this>a);} 77 bool operator >= (const Big &a)const{return !(*this<a);} 78 bool operator == (const Big &a) const{return !(*this<a||*this>a);} 79 bool operator != (const Big &a)const{return *this<a||*this>a;} 80 }; 81 void print(Big w){ 82 for(register int i=w.len-1;~i;i--) 83 printf("%d",w.s[i]); 84 puts(""); 85 }
线性求逆元
inv[1]=1; for(register int i=2;i<=n;i++) inv[i]=1ll*(p-p/i)*inv[p%i]%p;
线性筛欧拉函数值
phi[1]=1; for(register int i=2;i<=n;i++){ if(!v[i]) prm[++prm[0]]=i,phi[i]=i-1; for(register int j=1;j<=prm[0]&&i*prm[j]<=n;j++){ v[i*prm[j]]=1; if(i%prm[j]) phi[i*prm[j]]=phi[i]*(prm[j]-1); else{ phi[i*prm[j]]=phi[i]*prm[j]; break; } } }
快速幂+线性筛(快速求1~n的k次幂,n=1e7,O(nlog)卡不过去)
mi[1]=1; for(register int i=2;i<=n;i++){ if(!v[i]) prm[++prm[0]]=i,mi[i]=qpow(i,k); for(register int j=1;j<=prm[0]&&i*prm[j]<=n;j++){ v[i*prm[j]]=1; mi[i*prm[j]]=mi[i]*mi[prm[j]]%mod; if(i%prm[j]==0) break; } }
拓展 快速幂+线性筛 求$sumlimits_{i=1}^{n}i^k \% m$ n=1e18 m=3e6
利用上面的线筛筛出1~m的k次幂
然后化式子为$sumlimits_{i=1}^{n}(i\%m)^k \% m$ ,1~m的k次幂加和乘上循环节个数再加上末尾余下的几个k次幂
平方和公式
$largesumlimits_{i=1}^{n} i^2=frac{n*(n+1)*(2*n+1)}{6}$
树链剖分(线段树维护DFS序)
1 int n,to[21000],nex[21000],head[11000],len[21000],tot=1; 2 int dfn[11000],top[11000],size[11000],rk[11000],c[11000],cet,fa[11000],son[11000],dis[11000]; 3 int maxn[41000]; 4 void add(int x,int y,int z){ 5 to[++tot]=y,nex[tot]=head[x],head[x]=tot,len[tot]=z; 6 } 7 void dfs(int x,int pre){ 8 size[x]=1; 9 top[x]=x; 10 fa[x]=pre; 11 dis[x]=dis[pre]+1; 12 for(register int i=head[x];i;i=nex[i]){ 13 int y=to[i]; 14 if(y==pre) continue; 15 c[y]=len[i],len[i^1]=len[i]=y; 16 dfs(y,x); 17 son[x]=size[son[x]]>size[y]?son[x]:y; 18 size[x]+=size[y]; 19 } 20 } 21 void DFS(int x,int pre){ 22 dfn[x]=++cet; 23 rk[cet]=x; 24 if(son[x]) top[son[x]]=top[x],DFS(son[x],x); 25 for(register int i=head[x];i;i=nex[i]){ 26 int y=to[i]; 27 if(y==pre||y==son[x]) continue; 28 DFS(y,x); 29 } 30 } 31 void build(int t,int l,int r){ 32 if(l==r){ 33 maxn[t]=c[rk[l]]; 34 return; 35 } 36 int mid=(l+r)>>1; 37 build(t*2,l,mid); 38 build(t*2+1,mid+1,r); 39 maxn[t]=max(maxn[t*2],maxn[t*2+1]); 40 } 41 void change(int t,int l,int r,int x,int k){ 42 if(l==r){ 43 maxn[t]=k; 44 return; 45 } 46 int mid=(l+r)>>1; 47 if(mid>=x) change(t*2,l,mid,x,k); 48 else change(t*2+1,mid+1,r,x,k); 49 maxn[t]=max(maxn[t*2],maxn[t*2+1]); 50 } 51 int ask(int t,int l,int r,int L,int R){ 52 if(L>R) return 0; 53 if(L<=l&&r<=R) return maxn[t]; 54 int mid=(l+r)>>1,ans=0; 55 if(mid>=L) ans=max(ans,ask(t*2,l,mid,L,R)); 56 if(mid<R) ans=max(ans,ask(t*2+1,mid+1,r,L,R)); 57 return ans; 58 } 59 int query(int x,int y){ 60 int xx=top[x],yy=top[y],ans=0; 61 while(xx!=yy){ 62 if(dis[xx]>dis[yy]) ans=max(ans,ask(1,1,n,dfn[xx],dfn[x])),x=fa[xx],xx=top[x]; 63 else ans=max(ans,ask(1,1,n,dfn[yy],dfn[y])),y=fa[yy],yy=top[y]; 64 } 65 if(dis[x]>dis[y]) swap(x,y); 66 ans=max(ans,ask(1,1,n,dfn[x]+1,dfn[y])); 67 return ans; 68 }
数位DP
1 int a[20],dp[20][2]; 2 int dfs(int pos,int pre,int sta,bool limit){ 3 if(pos==-1) return 1; 4 if(!limit&&dp[pos][sta]!=-1) return dp[pos][sta]; 5 int up=limit?a[pos]:9; 6 int ans=0; 7 for(int i=0;i<=up;i++){ 8 if(pre==6&&i==2) continue; 9 if(i==4) continue; 10 ans+=dfs(pos-1,i,i==6,limit&&i==a[pos]); 11 } 12 if(!limit) dp[pos][sta]=ans; 13 return ans; 14 } 15 int solve(int x){ 16 int pos=0; 17 while(x){ 18 a[pos++]=x%10; 19 x/=10; 20 } 21 return dfs(pos-1,-1,0,true); 22 }
KD-Tree
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> using namespace std; int n,maximum,minimum,sz,now,ans; struct Point{ int x[2]; }sour[510000]; int comp(Point a,Point b){ return a.x[now]<b.x[now]; } int dis(Point a,Point b){ return abs(a.x[0]-b.x[0])+abs(a.x[1]-b.x[1]); } struct KD_Tree{ KD_Tree *ch[2]; Point ponit; int maxn[2],minn[2]; void redef(Point a){ ponit=a,minn[0]=maxn[0]=a.x[0],minn[1]=maxn[1]=a.x[1],ch[0]=ch[1]=NULL; } void update(KD_Tree *a){ minn[0]=min(minn[0],a->minn[0]),maxn[0]=max(maxn[0],a->maxn[0]); minn[1]=min(minn[1],a->minn[1]),maxn[1]=max(maxn[1],a->maxn[1]); } void pushup(){ if(ch[0]) update(ch[0]); if(ch[1]) update(ch[1]); } int calc_min(Point a){ return max(minn[0]-a.x[0],0)+max(a.x[0]-maxn[0],0)+max(minn[1]-a.x[1],0)+max(a.x[1]-maxn[1],0); } int calc_max(Point a){ return max(abs(a.x[0]-minn[0]),abs(a.x[0]-maxn[0]))+max(abs(a.x[1]-minn[1]),abs(a.x[1]-maxn[1])); } }*root,tr[510000]; void build(KD_Tree *&p,int l,int r,int d){ if(l>r) return; p=tr+(sz++),now=d; nth_element(sour+l,sour+((l+r)/2),sour+(r+1),comp); p->redef(sour[((l+r)/2)]); build(p->ch[0],l,((l+r)/2)-1,d^1); build(p->ch[1],((l+r)/2)+1,r,d^1); p->pushup(); } void query_max(KD_Tree *p,Point cmp){ if(p==NULL) return; maximum=max(dis(p->ponit,cmp),maximum); int Dis[2]={p->ch[0]==NULL?0:p->ch[0]->calc_max(cmp),p->ch[1]==NULL?0:p->ch[1]->calc_max(cmp)}; int first=Dis[0]>Dis[1]?0:1; if(Dis[first]>maximum) query_max(p->ch[first],cmp); if(Dis[first^1]>maximum) query_max(p->ch[first^1],cmp); } void query_min(KD_Tree *p,Point cmp){ if(p==NULL) return; if(dis(p->ponit,cmp)) minimum=min(dis(p->ponit,cmp),minimum); int Dis[2]={p->ch[0]==NULL?0x7f7f7f7f:p->ch[0]->calc_min(cmp),p->ch[1]==NULL?0x7f7f7f7f:p->ch[1]->calc_min(cmp)}; int first=Dis[0]<Dis[1]?0:1; if(Dis[first]<minimum) query_min(p->ch[first],cmp); if(Dis[first^1]<minimum) query_min(p->ch[first^1],cmp); } int query_max(Point cmp){ maximum=0,query_max(root,cmp); return maximum; } int query_min(Point cmp){ minimum=0x7fffffff,query_min(root,cmp); return minimum; } int main(){ scanf("%d",&n); ans=0x7f7f7f7f; for(int i=1;i<=n;i++) scanf("%d%d",&sour[i].x[0],&sour[i].x[1]); build(root,1,n,0); for(int i=1;i<=n;i++){ ans=min(ans,query_max(sour[i])-query_min(sour[i])); } printf("%d ",ans); }
插头DP
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n,m; const int mod=2601,p=1e9; struct node{ int bit[10]; void clear(){memset(bit,0,sizeof(bit));} node operator + (node b){ node c;c.clear(); c.bit[0]=max(b.bit[0],bit[0])+1; for(int i=1;i<=c.bit[0];i++){ c.bit[i]+=b.bit[i]+bit[i],c.bit[i+1]=c.bit[i]/p,c.bit[i]%=p; } while(!c.bit[c.bit[0]]) c.bit[0]--; return c; } void operator += (node b){*this=*this+b;} }ans; struct Hash{ int key[2601],hash[2601],size; node val[2601]; void clear(){ size=0; memset(key,-1,sizeof(key)); memset(val,0,sizeof(val)); memset(hash,0,sizeof(hash)); } void insert(const int state,node c){ for(int i=state%mod;;i=(i+1==mod)?0:i+1){ if(!hash[i]){ hash[i]=++size; key[size]=state; val[size].clear(); val[size]+=c; return; } if(key[hash[i]]==state){ val[hash[i]]+=c; return; } } } }f[2]; int set(int &state,int y,int s){ state|=(3<<((y-1)<<1)); state^=((3^s)<<((y-1)<<1)); } int find(int state,int pos){ int s=state>>((pos-1)<<1)&3; int cnt=0,i,t=(s==1)?1:-1; for(i=pos;i&&i<=m+1;i+=t){ int w=state>>((i-1)<<1)&3; if(w==1) cnt++; else if(w==2) cnt--; if(cnt==0) return i; } return -1; } int main(){ ans.clear(); scanf("%d%d",&n,&m); if(n==1||m==1){ printf("1 "); return 0; } if(n<m) swap(n,m); int cur=0; f[cur].clear(); node a; a.clear(); a.bit[++a.bit[0]]=1; f[0].insert(0,a); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ cur^=1; f[cur].clear(); int upw=f[cur^1].size; for(int k=1;k<=upw;k++){ int last=f[cur^1].key[k]; node val;val.clear(); val+=f[cur^1].val[k]; int plug1=(last>>((j-1)<<1))&3,plug2=(last>>(j<<1))&3; if(last<0) return 0; //if(find(last,j)==-1||find(last,j+1)==-1) continue; if(!plug1&&!plug2){ if(i!=n&&j!=m){ set(last,j,1); set(last,j+1,2); f[cur].insert(last,val); } } else if(plug1&&!plug2){ if(i!=n) f[cur].insert(last,val); if(j!=m) set(last,j,0),set(last,j+1,plug1),f[cur].insert(last,val); } else if(!plug1&&plug2){ if(j!=m) f[cur].insert(last,val); if(i!=n) set(last,j+1,0),set(last,j,plug2),f[cur].insert(last,val); } else if(plug1==1&&plug2==1){ set(last,find(last,j+1),1),set(last,j,0),set(last,j+1,0),f[cur].insert(last,val); } else if(plug1==1&&plug2==2){ if(i==n&&j==m) ans+=val; } else if(plug1==2&&plug2==2){ set(last,find(last,j),2),set(last,j,0),set(last,j+1,0),f[cur].insert(last,val); } else if(plug1==2&&plug2==1){ set(last,j,0),set(last,j+1,0),f[cur].insert(last,val); } } } if(i!=n){ int now=(i*m)&1,tot=f[now].size; for(int j=1;j<=tot;j++) f[now].key[j]<<=2; } } ans+=ans; printf("%d",ans.bit[ans.bit[0]]); for(int i=ans.bit[0]-1;i>=1;i--) printf("%09d",ans.bit[i]); }
手写堆
int match[110000],top;//match 记录某一个值所在堆中的标号 struct Queue{ int val,pos; Queue(int a=0,int b=0){val=a,pos=b;} }h[110000]; inline void up(int i){ //while(i>1&&h[i].val<h[i>>1].val)//小根堆 while(i>1&&h[i].val>h[i>>1].val)//大根堆 match[h[i>>1].pos]=i,swap(h[i>>1],h[i]),i>>=1; match[h[i].pos]=i; } inline void down(int i){ int to; while((i<<1)<=top){ to=(i<<1); // if(to<top&&h[to+1].val<h[to].val) ++to; //小根堆 if(to<top&&h[to+1].val>h[to].val) ++to; //大根堆 // if(h[to].val<h[i].val)//小根堆 if(h[to].val>h[i].val) //大根堆 match[h[to].pos]=i,swap(h[i],h[to]),i=to; else break; } match[h[i].pos]=i; } inline void push(int val,int pos){h[++top]=Queue(val,pos);up(top);} inline void pop(int i){ //h[i].val=0x7fffffff; //小根堆 h[i].val=-0x7fffffff;//大根堆 down(i); }
CDQ分治
void CDQ(int l,int r){ if(l==r) return; int mid=(l+r)/2,i=l,j=mid+1,p=l; CDQ(l,mid),CDQ(mid+1,r); while(i<=mid&&j<=r){ //if(v[j].id==2||v[j].id==3) cout<<v[j].id<<" "<<ask(v[j].c)<<endl; if(v[i].b<=v[j].b) add(v[i].c,v[i].cnt),tmp[p++]=v[i++]; else num[v[j].id]+=ask(v[j].c),tmp[p++]=v[j++]; } while(i<=mid) add(v[i].c,v[i].cnt),tmp[p++]=v[i++]; while(j<=r) num[v[j].id]+=ask(v[j].c),tmp[p++]=v[j++]; for(int k=l;k<=mid;k++) add(v[k].c,-v[k].cnt); for(int k=l;k<=r;k++) v[k]=tmp[k]; }
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; int n,m,tr[210000],num[110000],ans[110000]; struct node{ int a,b,c,id,cnt; }w[110000],v[110000],tmp[110000]; int cmp(node x,node y){ return x.a==y.a?((x.b==y.b)?(x.c<y.c):(x.b<y.b)):x.a<y.a; } int lowbit(int x){return x&(-x);} void add(int x,int k){ while(x<=m){ tr[x]+=k; x+=lowbit(x); } } int ask(int x){ int ans=0; while(x){ ans+=tr[x]; x-=lowbit(x); } return ans; } void CDQ(int l,int r){ if(l==r) return; int mid=(l+r)/2,i=l,j=mid+1,p=l; CDQ(l,mid),CDQ(mid+1,r); while(i<=mid&&j<=r){ //if(v[j].id==2||v[j].id==3) cout<<v[j].id<<" "<<ask(v[j].c)<<endl; if(v[i].b<=v[j].b) add(v[i].c,v[i].cnt),tmp[p++]=v[i++]; else num[v[j].id]+=ask(v[j].c),tmp[p++]=v[j++]; } while(i<=mid) add(v[i].c,v[i].cnt),tmp[p++]=v[i++]; // cout<<l<<" "<<mid<<" "<<r<<" "<<tr[1]<<" "<<tr[2]<<" "<<tr[3]<<endl; while(j<=r) num[v[j].id]+=ask(v[j].c),tmp[p++]=v[j++]; for(int k=l;k<=mid;k++) add(v[k].c,-v[k].cnt); for(int k=l;k<=r;k++) v[k]=tmp[k]; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d%d%d",&w[i].a,&w[i].b,&w[i].c); w[i].id=i; } sort(w+1,w+n+1,cmp); int tot=0; for(int i=1;i<=n;i++){ if(w[i].a!=w[i-1].a||w[i].b!=w[i-1].b||w[i].c!=w[i-1].c) v[++tot]=w[i]; v[tot].cnt++; } //cout<<endl; //for(int i=1;i<=tot;i++) printf("%d %d %d %d %d ",v[i].a,v[i].b,v[i].c,v[i].id,v[i].cnt); CDQ(1,tot); for(int i=1;i<=tot;i++){ //cout<<i<<" "<<num[v[i].id]<<endl; ans[num[v[i].id]+v[i].cnt-1]+=v[i].cnt; } for(int i=0;i<n;i++){ printf("%d ",ans[i]); } }
莫队
for(register int i=1;i<=m;i++){ while(l<q[i].l) chg(l++,-1); while(l>q[i].l) chg(--l,1); while(r>q[i].r) chg(r--,-1); while(r<q[i].r) chg(++r,1); ans[q[i].id]=a[1].sum; }
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; int n,m; long long a[51000],b[51000],c[51000],tmp[51000]; struct node{ int l,r,id; long long x,y; }q[51000]; long long cmp(node a,node b){ return a.l==b.l?a.r<b.r:a.l<b.l; } long long gcd(long long a,long long b){ return b?gcd(b,a%b):a; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%lld",&c[i]); for(int i=1;i<=m;i++) scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i; sort(q+1,q+m+1,cmp); int l=1,r=1; tmp[c[1]]++; long long res=1; for(int i=1;i<=m;i++){ while(l<q[i].l) res=res-tmp[c[l]]*2+1,tmp[c[l++]]--; while(l>q[i].l) res=res+tmp[c[--l]]*2+1,tmp[c[l]]++; while(r>q[i].r) res=res-tmp[c[r]]*2+1,tmp[c[r--]]--; while(r<q[i].r) res=res+tmp[c[++r]]*2+1,tmp[c[r]]++; q[i].x=res-(r-l+1); q[i].y=(long long)(r-l+1)*(r-l); if(q[i].x==0) a[q[i].id]=0,b[q[i].id]=1; else{ long long g=gcd(q[i].x,q[i].y); a[q[i].id]=q[i].x/g,b[q[i].id]=q[i].y/g; } } for(int i=1;i<=m;i++) printf("%lld/%lld ",a[i],b[i]); }
BSGS(比较好理解而且短的板子,附上Lockey的详细说明~)
long long pow(long long a,long long b,long long mod){ long long ans=1; a%=mod; while(b){ if(b&1) ans=ans*a%mod; b>>=1; a=a*a%mod; } return ans%mod; } //求 A^x同余Bzai在模p意义下 // 设m=sqrt(p),x=i*m-j //则 A^(i*m-j) %p=B // A^(i*m) %p= B*A^j %p //预处理 B*A^j%p 用hash存起来(可以用map,hash[B*A^j%p]=j), //枚举 i 计算 A^(i*m) 如果存在 A^(i*m)%p=B*A^j%p ,则hash[A^(i*m)%p]=j //最终ans=i*m-j; long long BSGS(long long y,long long z,long long p){ //开头加点儿特判啥的都可以 hs.clear();//千万不要用hash这个名字,会CE long long m=ceil(sqrt(p*1.0)),s=z%p,t; hs[s]=0; for(int i=1;i<=m;i++){ s=s*y%p; hs[s]=i;//将 B*A^j%p 存进hash表 } t=pow(y,m,p),s=1; for(int i=1;i<=m;i++){ s=s*t%p; if(hs[s]){//找到符合条件的j ans=i*m-hs[s];//得出答案 return ans; } } return -1; }
#include<iostream> #include<cstdio> #include<map> #include<cmath> using namespace std; long long T,p,a,b,x1,t; map<long long,int>hs; long long pow(long long a,long long b,long long p){ long long ans=1; a%=p; while(b){ if(b&1) ans=ans*a%p; b>>=1; a=a*a%p; } return ans%p; } void BSGS(long long a,long long b,long long p){ hs.clear(); // a%=p,b%=p; long long m=ceil(sqrt(p*1.0)),s=b%p,t; hs[s]=0; for(int i=1;i<=m;i++) s=s*a%p,hs[s]=i; t=pow(a,m,p),s=1; for(int i=1;i<=m;i++){ s=s*t%p; if(hs[s]){ printf("%lld ",i*m-hs[s]+1); return; } } printf("-1 "); return; } int main(){ scanf("%lld",&T); while(T--){ scanf("%lld%lld%lld%lld%lld",&p,&a,&b,&x1,&t); b%=p; a%=p; if(x1==t) printf("1 "); else if(a==0&&t==b) printf("2 "); else if(a==0&&t!=b) printf("-1 "); else if(a==1){ if(b==0) printf("-1 "); else printf("%lld ",(t-x1+p)%p*pow(b,p-2,p)%p+1); } else{ int B=(((t-b*pow(1-a,p-2,p))+p)%p*pow(x1-b*pow(1-a,p-2,p),p-2,p)+p)%p; BSGS(a,B,p); } } }
dijistra(堆优化)板子
long long dis[11000],v[11000]; struct node{ int to,len; }; struct haha{ long long x,d; haha(long long a,long long b){x=a,d=b;} }; struct cmp{ bool operator () (haha &a,haha &b){ return a.d>b.d; } }; vector<node>son[11000]; long long min(long long a,long long b){ return a<b?a:b; } void dijkstra(int w){ priority_queue<haha,vector<haha>,cmp>q; dis[1]=0; q.push(haha(1,0)); while(!q.empty()){ int x=q.top().x; q.pop(); v[x]=1; for(int k=0;k<son[x].size();k++){ if(x==1&&k==w) continue; int y=son[x][k].to,len=son[x][k].len; if(!v[y]&&dis[y]>dis[x]+len){ dis[y]=dis[x]+len; q.push(haha(y,dis[y])); } } } }
高精乘除低精
void multi(int x){//高精乘低精 int tmp=0; for(int i=1;i<=ans[0];i++){ tmp=ans[i]*x+tmp; ans[i]=tmp%10; tmp=tmp/10; } while(tmp) ans[++ans[0]]=tmp%10,tmp/=10; } void div(int x){//高精除低精 int tmp=0; for(int i=ans[0];i>=1;i--){ tmp+=ans[i]; ans[i]=tmp/x; tmp%=x; tmp*=10; } while(ans[ans[0]]==0&&ans[0]>1) ans[0]--; }
欧拉函数值求解
欧拉函数用希腊字母φ表示,φ(N)表示N的欧拉函数. 对φ(N)的值,我们可以通俗地理解为小于N且与N互质的数的个数(包含1). 欧拉函数的一些性质: 1.对于素数p, φ(p)=p-1,对于对两个素数p,q φ(pq)=pq-1 欧拉函数是积性函数,但不是完全积性函数. 2.对于一个正整数N的素数幂分解N=P1^q1*P2^q2*...*Pn^qn. φ(N)=N*(1-1/P1)*(1-1/P2)*...*(1-1/Pn). 3.除了N=2,φ(N)都是偶数. 4.设N为正整数,∑φ(d)=N (d|N).
int euler(int x){ int phi=x; for(int i=2;i<=x;i++){ if(x%i==0){ phi/=i*(i-1); while(x%i==0) x/=i; } } if(x>1) phi/=x*(x-1); return phi; }
1 phi[1]=1; 2 for(register int i=2;i<=10000000;i++){ 3 if(!phi[i]) phi[i]=i-1,prm[++prm[0]]=i; 4 for(register int j=1;j<=prm[0]&&i*prm[j]<=10000000;j++){ 5 if(i%prm[j]==0){phi[i*prm[j]]=phi[i]*prm[j];break;} 6 else phi[i*prm[j]]=phi[i]*(prm[j]-1); 7 } 8 }
组合数取模7种类型(尤其是模数为非质数)(重点)
类型0:n,m<=1000 直接暴力预处理杨辉三角,预处理复杂度O(n*n) 公式:C(n,m)=C(n,n-m)=C(n-1,m-1)+C(n-1,m) 类型1:n,m<=1e6 且模数p是质数。 O(n)预处理 阶乘fac[i]和阶乘的逆ifac即可。然后 C(n,m)=fac[n]*ifac[m]*ifac[n-m] 预处理复杂度O(n),查询O(1)。HDU6333 Problem B. Harvest of Apples 莫队算法+逆元 类型2:n,m <=1e18 且模数p为质数,且p<=1e5,用Lucas定理,展开成多个组合数的乘积。 单次查询复杂度O(p*log(n)/log(p)) HDU3037 Saving Beans Lucas 定理+逆元 类型3:n,m,p <=1e18 且模数p为非质数,用Lucas定理+中国剩余定理 单次查询复杂度O(VY*p*log(n)/lop(p))V,Y为p的质因子个数和幂次 HDU5446 Unknown Treasur Lucas+中国剩余定理 类型4:n<=1e9,m<=1e5, p<=1e9且为质数,用逆元暴力计算C(n,m)=n*(n-1)*(n-2)*……*(n-m+1)/(1*2*……*m) 算法复杂度O(m) 类型5: n,m<=1e5,mod非质数, 对阶乘分解质因数,然后跑快速幂,算法复杂度O(n)
for(int i=2;i<=n*2;i++){ if(!vis[i]) prim[++prim[0]]=i; for(int j=1;j<=prim[0]&&i*prim[j]<=n*2;j++){ vis[i*prim[j]]=1; if(i%prim[j]==0) break; } } for(int i=1;i<=prim[0];i++){ for(int j=n*2;j/=prim[i];) a[i]+=j; for(int j=n;j/=prim[i];) a[i]-=j; for(int j=n+1;j/=prim[i];) a[i]-=j; ans=(ans*pow(prim[i],a[i]))%mod; }
可以看一下这篇博客 证明时间复杂度为O(n) 可以看Yu_shi的博客
long long china(){ long long ans=0; for(int i=1;i<=prm[0];i++){ long long a=mod/prm[i]; exgcd(a,prm[i]); ans=(ans+a*x*b[i]%mod)%mod; } if(ans>=0) return ans; else return ans%mod+mod; }
long long pow(long long a,long long b,long long p){ long long ans=1; a%=p; while(b){ if(b&1) ans=ans*a%p; b>>=1; a=a*a%p; } return ans%p; } long long C(int n,int m,int p){ if(n<m) return 0; else return fac[n]%p*pow(fac[n-m]*fac[m]%p,p-2,p)%p; } long long lucas(int a,int b,int p){ if(!b) return 1; else return lucas(a/p,b/p,p)%p*C(a%p,b%p,p)%p; }
prufer序列
高斯消元
1 void gauss(){ 2 for(int i=1;i<=n;i++){ 3 int p=i; 4 for(int j=i+1;j<=n;j++) 5 if(fabs(a[j][i])>fabs(a[p][i])) p=j; 6 for(int j=1;j<=n+1;j++) swap(a[i][j],a[p][j]); 7 if(fabs(a[i][i])<eps) continue; 8 double tem=a[i][i]; 9 for(int j=1;j<=n+1;j++) a[i][j]/=tem; 10 for(int j=1;j<=n;j++) 11 if(i!=j){ 12 tem=a[j][i]; 13 for(int k=1;k<=n+1;k++) a[j][k]-=a[i][k]*tem; 14 } 15 } 16 }
分治消元(消后一半求前一半,还原后小前一半求后一半)
1 struct node{ 2 int a[310][310]; 3 }st[15]; 4 int a[310][310],ans[310]; 5 void gouss(int i,int l,int r){ 6 long long tmp=qpow(a[i][i],mod-2); 7 for(register int j=1;j<=n+1;j++) a[i][j]=tmp*a[i][j]%mod; 8 for(register int j=1;j<=n;j++){ 9 if(i==j) continue; 10 tmp=a[j][i]; 11 for(register int k=l;k<=r;k++){ 12 a[j][k]=(a[j][k]-tmp*a[i][k])%mod; 13 } 14 a[j][n+1]=(a[j][n+1]-tmp*a[i][n+1])%mod; 15 } 16 } 17 void solve(int l,int r){ 18 if(l==r){ 19 ans[l]=a[1][n+1]; 20 return; 21 } 22 top++; 23 for(register int i=1;i<=n;i++){ 24 for(register int j=1;j<=n+1;j++){ 25 st[top].a[i][j]=a[i][j]; 26 } 27 } 28 int mid=(l+r)>>1; 29 for(register int i=mid+1;i<=r;i++) gouss(i,l,r); 30 solve(l,mid); 31 for(register int i=1;i<=n;i++){ 32 for(register int j=1;j<=n+1;j++){ 33 a[i][j]=st[top].a[i][j]; 34 } 35 } 36 for(register int i=l;i<=mid;i++) gouss(i,l,r); 37 solve(mid+1,r); 38 top--; 39 }