ACM模板

优化

#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#pragma GCC optimize(3 , "Ofast" , "inline")
#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")
#pragma GCC optimization("unroll-loops")
  //   freopen("C://Users//spnooyseed//Desktop//in.txt" , "r" , stdin) ;
  //   freopen("C://Users//spnooyseed//Desktop//out.txt" , "w" , stdout) ;

最小环路径

ll n , m , g[110][110] , dis[110][110] , z[110][110] ;
ll ans = INF ;
vector<int> v ;
void floyd()
{
  for(int k = 1 ;k <= n ;k ++){
     for(int i = 1 ;i < k ;i ++ ){
        for(int j = i + 1; j < k ;j ++){
           ll temp = g[i][k] + g[k][j] + dis[i][j] ;
           if(temp < ans){
              ans = temp ,v.clear() ;
              int p = j ;
              while(p != i){
                 v.push_back(p) ;
                 p = z[i][p] ;
               }
               v.push_back(i),v.push_back(k) ;
            }
         }
      }
      for(int i = 1; i <= n ;i ++)
       for(int j = 1; j <= n ;j ++){
          ll temp = dis[i][k] + dis[k][j] ;
          if(dis[i][j] > temp)
           dis[i][j] = temp , z[i][j] = z[k][j] ;
        }
   }
}
int main()
{
  n = in() , m = in() ;
  for(int i = 0 ;i < 102 ;i ++)
   for(int j = 0 ; j < 102 ;j ++)
    g[i][j] = INF , dis[i][j] = INF , z[i][j] = i ;
  for(int i = 1; i <= m ;i ++)
   {
     ll u = in() , v = in() , w = in() ;
     g[u][v] = g[v][u] = dis[u][v] = dis[v][u] = min(dis[u][v] , w) ;
   }
  floyd() ;
  if(ans == INF) puts("No solution.") ;
  else
   {
     for(auto x : v)
      cout << x << " " ;
   }
  return 0 ;
}

二分匹配

匈牙利匹配
int find(int u){
  for(auto x : v[u]){
     if(!st[x]){
        st[x] = 1 ;
        if(match[x] == 0 || find(match[x])){
           match[x] = u ;
           return true ;
         }
      }
   }
   return false ;
}
int main()
{
  cin >> n >> m ;
  int a , b ;
  while(cin >> a >> b)
   v[a].push_back(b) ;
  int res = 0 ;
  for(int i = 1 ;i <= n - m ;i ++){
     memset(st , 0 , sizeof st) ;
     if(find(i))
      res ++ ;
   }
  cout << res << endl ;
}
HK二分匹配
int dx[N] , dy[N] , n , m ;
vector<int> v[N] ;
int vis[N] , match[N] , usedx[N] , usedy[N] , depth;
bool find(int u) {
  for(auto x : v[u]) {
    if(!vis[x] && dx[u] == dy[x] - 1) {
      vis[x] = 1 ;
      if(!usedy[x] || find(usedy[x])) {
        usedx[u] = x ;
        usedy[x] = u ;
        return true ;
      }
    }
  }
  return false ;
}
bool bfs() {
  queue<int> q ;
  depth = INF ;
  memset(dx , -1 , sizeof dx) ;
  memset(dy , -1 , sizeof dy) ;
  for(int i = 1; i <= n ;i ++ )
   if(!usedx[i]) dx[i] = 0 , q.push(i) ;
  while(q.size()) {
    int u = q.front() ;q.pop() ;
    if(depth < dx[u]) break ;
    for(auto x : v[u]) {
      if(dy[x] == -1) {
        dy[x] = dx[u] + 1 ;
        if(!usedy[x]) depth = dy[x] ;
        else dx[usedy[x]] = dy[x] + 1 , q.push(usedy[x]) ;
      }
    }
  }
  return depth != INF ;
}
int work()
{

  memset(usedx , 0 , sizeof usedx) ;
  memset(usedy , 0 , sizeof usedy) ;
  while(bfs()) {
    memset(vis , 0 , sizeof vis) ;
    for(int i = 1 ;i <= n ;i ++ )
     if(!usedx[i] && find(i))
      ans ++ ;
  }
  cout << ans << endl ;
  return 0 ;
}
KM带权二分匹配
int love[N][N] , ex_girl[N] , ex_boy[N] , vis_girl[N] , vis_boy[N];
int match[N] , slack[N] , n ;
bool dfs(int girl){
	vis_girl[girl] = true ;
	for(int boy = 0 ;boy < n ;boy ++){
		if(vis_boy[boy]) continue ;
		int gap = ex_girl[girl] + ex_boy[boy] - love[girl][boy] ;
		if(gap == 0){
		 	vis_boy[boy] = true ;
		 	if(match[boy] == -1 || dfs(match[boy])) {
			  	match[boy] = girl ;
			  	return true ;
			  }
		 }
		 else slack[boy] = min(slack[boy] , gap) ;
	}
	return false ;
}
int KM(){
	memset(match , -1 , sizeof match) ;
	memset(ex_boy , 0 , sizeof ex_boy) ;
	for(int i = 0 ;i < n ;i ++)
	 	for(int j = 0 ;j < n ;j ++)
	 	 ex_girl[i] = max(ex_girl[i] , love[i][j]) ;
    for(int i = 0 ;i < n ;i ++)   {
     	memset(slack , INF , sizeof slack) ;
     	while(1) {
     	 	memset(vis_girl , 0 , sizeof vis_girl) ;
     	 	memset(vis_boy , 0 , sizeof vis_boy) ;
     	 	if(dfs(i)) break ;
     	 	int d = INF ;
     	 	for(int j = 0 ;j < n ;j ++)
     	 	 if(!vis_boy[j])
     	 	  d = min(d , slack[j]) ;
        for(int j = 0 ;j < n ;j ++){
     	 	 	if(vis_girl[j]) ex_girl[j] -= d ;
     	 	 	if(vis_boy[j]) ex_boy[j] += d ;
     	 	 	else slack[j] -= d ;
			 }
		 }
	 }
	 int res = 0 ;
	 for(int i = 0 ;i < n ;i ++)
	  res += love[match[i]][i] ;
	 return res ;
}
int main(){
    while(~scanf("%d" , &n)){
     	for(int i = 0 ;i < n ;i ++)
     	 for(int j = 0 ;j < n ;j ++)
     	  scanf("%d" , &love[i][j]) ;
     	printf("%d
" , KM()) ;
	 }
	return 0 ;
}
//O^3
void bfs( ll k ){
    ll x , y = 0 , yy = 0 , delta;
    memset( pre , 0 , sizeof(pre) );
    for( ll i = 1 ; i <= n ; i++ ) slack[i] = INF;
    linker[y] = k;
    while(1){
        x = linker[y]; delta = INF; visy[y] = true;
        for( ll i = 1 ; i <= n ;i++ ){
            if( !visy[i] ){
                if( slack[i] > lx[x] + ly[i] - w[x][i] ){
                    slack[i] = lx[x] + ly[i] - w[x][i];
                    pre[i] = y;
                }
                if( slack[i] < delta ) delta = slack[i] , yy = i ;
            }
        }
        for( ll i = 0 ; i <= n ; i++ ){
            if( visy[i] ) lx[linker[i]] -= delta , ly[i] += delta;
            else slack[i] -= delta;
        }
        y = yy ;
        if( linker[y] == -1 ) break;
    }
    while( y ) linker[y] = linker[pre[y]] , y = pre[y];
}
ll KM(){
    memset( lx , 0 ,sizeof(lx) );
    memset( ly , 0 ,sizeof(ly) );
    memset( linker , -1, sizeof(linker) );
    for( ll i = 1 ; i <= n ; i++ ){
        memset( visy , false , sizeof(visy) );
        bfs(i);
    }
    ll res = 0 ;
        for( ll i = 1 ; i <= n ; i++ ){
            if( linker[i] != -1 ){
                res += w[linker[i]][i] ;
            }
        }
        return res;
}
int main(){
    w[i][j]=s;
    printf("%lld
",KM());
}
带花树求一般图最大匹配
int findp(int x){return x==par[x]?x:par[x]=findp(par[x]);}
int Ti=0,times[maxn]={};
int lca(int x,int y){
   for(Ti++;times[x]!=Ti;x^=y^=x^=y)
       if(x) times[x]=Ti,x=findp(pre[link[x]]);
   return x;
}
void blossom(int x,int y,int p){
   while(findp(x)!=p){
       pre[x]=y;
       y=link[x];
       par[x]=par[y]=p;
       if(ty[y]==1) ty[y]=2,q.push_back(y);
       x=pre[y];
   }
}
bool Match(int x){
   for(int i=0;i<=n;i++) ty[i]=0,par[i]=i;
   q.clear();
   ty[x]=2,q.push_back(x);
   while(q.size()){
       x=q.front(),q.pop_front();
       for(int u:g[x])
           if(ty[u]==0){
               ty[u]=1;
               pre[u]=x;
               if(link[u]) q.push_back(link[u]),ty[link[u]]=2;
               else {
                   for(;x;u=x){
                       x=link[pre[u]];
                       link[u]=pre[u];
                       link[link[u]]=u;
                   }
                   return 1;
               }
           }
           else if(ty[u]==2&&findp(u)!=findp(x)){
               int p=lca(x,u);
               blossom(x,u,p),blossom(u,x,p);
           }
   }
   return 0;
}
int main(){
   mem(link,0);mem(pre,0);
   ans=0;
   scanf("%d",&n);
   for(int f,t;~scanf("%d%d",&f,&t);){
       g[f].push_back(t);
       g[t].push_back(f);
   }
   for(int i=1;i<=n;i++)
       if(!link[i]&&Match(i)) ans++;
   printf("%d
",ans*2);
   for(int i=1;i<=n;i++)
   	  if(i<link[i])
       printf("%d %d
",i,link[i]);
   	return 0 ;
}

二分匹配单侧多重匹配
int g[1010][1010] , vis[1010] , match[1010] , a[1010][1010]  ;
bool find(int u , int mid) {
  for(int i = 1; i <= m ;i ++ ) {
    if(g[u][i] && !vis[i]) {
      vis[i] = 1 ;
      if(a[i][0] < mid) {
        a[i][++ a[i][0]] = u ;
        match[u] = i ;
        return true ;
      }
      else if(a[i][0] == mid) {
        for(int j = 1 ;j <= mid ;j ++ ) {
          if(find(a[i][j] , mid)){
            a[i][j] = u ;
            match[a[i][j]] = i ;
            return true ;
          }
        }
      }
    }
  }
  return false ;
}
// 左边n , 右边m , 右边点可用多条边
bool check(int mid) {
  memset(match , 0 , sizeof match) ;
  memset(a , 0 , sizeof a) ;
  for(int i = 1; i <= n ;i ++ ) {
    memset(vis , 0 , sizeof vis) ;
    if(!find(i , mid)) return false ;
  }
  return true ;
}
int work(){
  while(cin >> n >> m) {
    if(n == 0 && m == 0) break ;
    memset(match , 0 , sizeof match) ;
    memset(g , 0 , sizeof g) ;
    for(int i = 1; i <= n ;i ++ ) {
      string s ;
      cin >> s ;
      int x ;
      char c ;
      while(scanf("%d%c" , &x , &c)) {
        g[i][x + 1] = 1 ;
        if(c == '
') break ;
      }
    }
    int l = 0 , r = n , ans = 0;
    while(l <= r) {
       int mid = l + r >> 1 ;
       if(check(mid)) r = mid - 1 , ans = mid ;
       else l = mid + 1 ;
    }
    cout << ans << endl ;
  }
  return 0 ;
}
一般图的最大匹配(每个点都有d[i]条边相连)
void Push(int u){
    que[tail]=u;
    tail++;
    inque[u]=1;
}
int Pop(){
    int res=que[head];
    head++;
    return res;
}
int lca(int u,int v)//寻找公共花祖先{
    memset(inpath,0,sizeof(inpath));
    while(1){
        u=base[u];
        inpath[u]=1;
        if(u==st) break;
        u=pre[match[u]];
    }
    while(1){
        v=base[v];
        if(inpath[v]) break;
        v=pre[match[v]];
    }
    return v;
}
void reset(int u)//缩环{
    int v;
    while(base[u]!=newbase){
        v=match[u];
        inhua[base[u]]=inhua[base[v]]=1;
        u=pre[v];
        if(base[u]!=newbase) pre[u]=v;
    }
}
void contract(int u,int v)//{
    newbase=lca(u,v);
    memset(inhua,0,sizeof(inhua));
    reset(u);
    reset(v);
    if(base[u]!=newbase) pre[u]=v;
    if(base[v]!=newbase) pre[v]=u;
    for(int i=1;i<=n;i++){
        if(inhua[base[i]]){
            base[i]=newbase;
            if(!inque[i])
                Push(i);
        }
    }
}
void findaug(){
    memset(inque,0,sizeof(inque));
    memset(pre,0,sizeof(pre));
    for(int i=1;i<=n;i++)//并查集  base[i]=i;
    head=tail=1;
    Push(st);
    ed=0;
    while(head<tail){
        int u=Pop();
        for(int v=1;v<=n;v++){
            if(g[u][v]&&(base[u]!=base[v])&&match[u]!=v){
                if(v==st||(match[v]>0)&&pre[match[v]]>0)//成环
                    contract(u,v);
                else if(pre[v]==0){
                    pre[v]=u;
                    if(match[v]>0)  Push(match[v]);
                    else//找到增广路ed=v,return ;
                }
            }
        }
    }
}
void aug(){
    int u,v,w;
    u=ed;
    while(u>0){
        v=pre[u];
        w=match[v];
        match[v]=u;
        match[u]=v;
        u=w;
    }
}
void edmonds()//匹配{
    memset(match,0,sizeof(match));
    for(int u=1;u<=n;u++){
        if(match[u]==0){
            st=u;
            findaug();//以st开始寻找增广路
            if(ed>0) aug();//找到增广路  重新染色,反向
        }
    }
}
//以上是带花树求最大匹配算法  不用看

void create()//建图{
    n=0;
    memset(g,0,sizeof(g));
    for(int i=1;i<=np;i++)
        for(int j=1;j<=f[i];j++)
            mp[i][j]=++n;//拆点,给每个度的点编号
    for(int i=0;i<ne;i++)
    {//此时n+1代表x,n+2代表y
        for(int j=1;j<=f[x[i]];j++)
            g[mp[x[i]][j]][n+1]=g[n+1][mp[x[i]][j]]=1;//每个度的点与对应的x,y相连
        for(int j=1;j<=f[y[i]];j++)
            g[mp[y[i]][j]][n+2]=g[n+2][mp[y[i]][j]]=1;
        g[n+1][n+2]=g[n+2][n+1]=1;//x与y相连
        n+=2;
    }
}
void print(){
    ans=0;
    for(int i=1;i<=n;i++)
        if(match[i]!=0){
              ans++;
//            if(match[i]>i)
//            cout<<"_____"<<i<<' '<<match[i]<<endl;
        }
    //cout<<"******"<<ans<<' '<<n<<endl;
    if(ans==n)    printf("Yes
");
    else    printf("No
");
}
int main(){
        while(~scanf("%d%d",&np,&ne)){
           for(int i=1;i<=np;i++)
            scanf("%d",&f[i]);
            for(int i=0;i<ne;i++)
            scanf("%d%d",&x[i],&y[i]);
            create();
            edmonds();
            print();
        }
    return 0;
}

tarjan

void tarjan(int u){
 // dfn 节点的时间戳 , low 当前强联通分量根节点的时间戳 , ssc[i] , 当前是第i个强连通分量
  // sc 强连通分量的个数 , sz[i] 强连通分量的大小
   low[u] = dfn[u] = ++dfncnt, s[++tp] = u;
   for (auto x : v[u] {
       if (!dfn[x])
           tarjan(x), low[u] = min(low[u], low[x]);
       else if (!scc[x])
           low[u] = min(low[u], dfn[x]);
   }
   if (dfn[u] == low[u]) {
       ++sc;
       while (s[tp] != u) scc[s[tp]] = sc, sz[sc]++, --tp;
       scc[s[tp]] = sc, sz[sc]++, --tp;
   }
}

tarjan 点双连通分量

int dfn[N] , low[N] , ans[N] , cnt = 0 ;
vector<int> v[N] ;
// ans[] 点所在几个点双连通分量
void tarjan(int u , int f) {
  low[u] = dfn[u] = ++ cnt ;
  ans[u] = 0 ;
  if(f) ans[u] ++ ;
  for(auto x : v[u]) {
    if(x == f) continue ;
    if(!dfn[x]) {
      tarjan(x , u) ;
      low[u] = min(low[u] , low[x]) ;
      if(low[x] < dfn[u]) ans[u] -- ;
      ans[u] ++ ;
    }else low[u] = min(low[u] , dfn[x]) ;
  }
}
int work(){
  for(int i = 1; i <= n ;i ++ ) if(!dfn[i]) tarjan(i , 0) , res ++ ;
}
tarjan边双连通分量
const int N = 5010;//点数
const int M = 20010;//边数,因为是无向图,所以这个值要 *2
struct Edge{
    int to,nxt;
    bool cut;//是否是桥标记
} edge[M];
int head[N],tot , low[N],dfn[N],sta[N],belong[N];//Belong 数组的值是1~block
int id,top , block;//边双连通块数
bool insta[N];
int bridge;//桥的数目
void add(int u,int v){
    edge[tot].to = v;
    edge[tot].nxt = head[u];
    edge[tot].cut=false;
    head[u] = tot++;
}
void Tarjan(int u,int pre){
    int v;
    low[u] = dfn[u] = ++id;
    sta[top++] = u;
    insta[u] = true;
    int pre_cnt = 0;
    for(int i = head[u]; i != -1; i = edge[i].nxt){
        v = edge[i].to;
        if(v == pre && pre_cnt == 0){
            pre_cnt++;
            continue;
        }
        if(!dfn[v]){
            Tarjan(v,u);
            if(low[u]>low[v]) low[u] = low[v];
            if(low[v]>dfn[u]) {
                bridge++;
                edge[i].cut = true;
                edge[i^1].cut = true;
            }
        }
        else if( insta[v] && low[u] > dfn[v] )  low[u] = dfn[v];
    }
    if(low[u] == dfn[u]){
        block++;
        do{
            v = sta[--top];
            insta[v] = false;
            belong[v] = block;
        }while( v!=u );
    }
}
void init(){
    tot = 0;
    memset(head,-1,sizeof(head));
}
int du[N];//缩点后形成树,每个点的度数
void solve(int n){
    memset(dfn,0,sizeof(dfn));
    memset(insta,false,sizeof(insta));
    id = top = block = 0;
    Tarjan(1,0);
    int ans = 0;
    memset(du,0,sizeof(du));
    for(int i = 1; i <= n; i++) for(int j = head[i]; j != -1; j = edge[j].nxt) if(edge[j].cut) du[belong[i]]++;
    for(int i = 1; i <= block; i++) if(du[i]==1) ans++; //找叶子结点的个数 ans, 构造边双连通图需要加边(ans+1)/2
    printf("%d
",(ans+1)/2);
}
int main(){
    int n,m;
    int u,v;
    while(scanf("%d%d",&n,&m)==2){
        init();
        while(m--){
            scanf("%d%d",&u,&v);
            add(u,v);
            add(v,u);
        }
        solve(n);
    }
    return 0;
}

割点与桥

void Tarjan(int i,int Father){
    father[i]=Father;/*记录每一个点的父亲*/
    dfn[i]=low[i]=tim++;
    for(int j=0;j<G[i].size();++j) {
        int k=G[i][j];
        if(dfn[k]==-1){
            Tarjan(k,i);
            low[i]=min(low[i],low[k]);
        }
        else if(Father!=k)/*假如k是i的父亲的话,那么这就是无向边中的重边,有重边那么一定不是桥*/
            low[i]=min(low[i],dfn[k]);//dfn[k]可能!=low[k],所以不能用low[k]代替dfn[k],否则会上翻过头了。
    }
}
void count(){
    int rootson=0;
    Tarjan(1,0);
    for(int i=2;i<=n;++i){
        int v=father[i];
        if(v==1)
        rootson++;/*统计根节点子树的个数,根节点的子树个数>=2,就是割点*/
        else{
            if(low[i]>=dfn[v])/*割点的条件*/
            is_cut[v]=true;
        }
    }
    if(rootson>1) is_cut[1]=true;
    for(int i=1;i<=n;++i)
         if(is_cut[i]) printf("%d
",i);
    for(int i=1;i<=n;++i){
        int v =father[i];
        if(v>0&&low[i]>dfn[v])/*桥的条件*/
        printf("%d,%d
",v,i);
    }
}
int main(){
    input();
    memset(dfn,-1,sizeof(dfn));
    memset(father,0,sizeof(father));
    memset(low,-1,sizeof(low));
    memset(is_cut,false,sizeof(is_cut));
    count();
    return 0;
}

网络流

最大流最小费用

int n,m;
int get(int x,int y)
{
   return x*m+y;
}
const int maxn=100100;
bool vis[maxn];
int s,t,dis[maxn],pre[maxn],last[maxn],flow[maxn],maxflow,mincost;
//dis最小花费;pre每个点的前驱;last每个点的所连的前一条边;flow源点到此处的流量
struct Edge{
   int to,next,flow,dis;//flow流量 dis花费
}edge[maxn];
int head[maxn],get_edge;
queue <int> q;
void add(int from,int to,int flow,int dis){
   edge[++get_edge].next=head[from];
   edge[get_edge].to=to;
   edge[get_edge].flow=flow;
   edge[get_edge].dis=dis;
   head[from]=get_edge;
}
void add_edge(int from , int to , int flow , int dis) {
 add(from , to , flow , dis) ;
 add(from , to , 0 , -dis) ;
}
bool spfa(int s,int t){
   memset(dis,0x7f,sizeof(dis));
   memset(flow,0x7f,sizeof(flow));
   memset(vis,0,sizeof(vis));
   q.push(s);vis[s]=1;dis[s]=0; pre[t]=-1;
   while (!q.empty()) {
       int now=q.front();
       q.pop();
       vis[now]=0;
       for (int i=head[now]; i!=-1; i=edge[i].next){
           if (edge[i].flow>0 && dis[edge[i].to]>dis[now]+edge[i].dis)//正边{
               dis[edge[i].to]=dis[now]+edge[i].dis;
               pre[edge[i].to]=now;
               last[edge[i].to]=i;
               flow[edge[i].to]=min(flow[now],edge[i].flow);//
               if (!vis[edge[i].to]){
                   vis[edge[i].to]=1;
                   q.push(edge[i].to);
               }
           }
       }
   }
   return pre[t]!=-1;
}
void MCMF(){
   while (spfa(s,t)){
       int now=t;
       maxflow+=flow[t];
       mincost+=flow[t]*dis[t];
       //cout<<maxflow<<" "<<mincost<<endl;
       while (now!=s)
       {//从源点一直回溯到汇点
           edge[last[now]].flow-=flow[t];//flow和dis容易搞混
           edge[last[now]^1].flow+=flow[t];
           now=pre[now];
       }
   }
}
int main(){
   memset(head,-1,sizeof head);
   get_edge=-1;
   t=n*m+100,s=n*m+200;
   MCMF();//cout<<maxflow<<" "<<mincost<<endl;
   if(maxflow!=2)printf("-1
");
   else printf("%d
",mincost);
   return 0;
}

Dinic最大流

struct node{
   int u, v, c, next;
}Node[2*N];
void add_(int u, int v, int c){
   Node[cnt].u = u;
   Node[cnt].v = v;
   Node[cnt].c = c;
   Node[cnt].next = head[u];
   head[u] = cnt++;
}
void add(int u, int v, int c){
   add_(u, v, c);
   add_(v, u, 0);
}
bool bfs(){
   queue<int> Q;
   memset(d , 0 , sizeof d) ;
   Q.push(s);
   d[s] = 1;
   while(!Q.empty()){
       int u = Q.front(); Q.pop();
       for(int i=head[u]; i!=-1; i=Node[i].next){
           node e = Node[i];
           if(!d[e.v] && e.c > 0){
               d[e.v] = d[e.u] + 1;
               Q.push(e.v);
               if(e.v == t) return 1;
           }
       }
   }
   return d[t] != 0;
}
int dfs(int u, int cap){
   int ret = 0, V;
   if(u == t || cap == 0)
       return cap;
   for(int &i=cur[u]; i!=-1; i=Node[i].next) {
       node e = Node[i];
       if(d[e.v] == d[u] +  1 && e.c > 0){
           int V = dfs(e.v, min(cap, e.c));
           Node[i].c -= V;
           Node[i^1].c += V;
           ret += V;
           cap -= V;
           if(cap == 0) break;
       }
   }
   if(cap > 0) d[u] = -1;
   return ret;
}
int dinic(int u){
   int ans = 0;
   while(bfs()) {
       memcpy(cur, head, sizeof(head));
       ans += dfs(u, INF);
   }
   return ans;
}
void init() {
 memset(head ,-1,  sizeof head) ;
 cnt = 0 ;
}

固定流量的最小费用

struct edge {
   int to, next, cap;
   ll cos;
}e[M<<1];
struct node {
   ll a, b, c;
}p[55];
vector<int> a[55], b;
int n, m, cnt, s, t, k;
void add(int u, int v, int cap, ll cos) {
   e[cnt].to = v;
   e[cnt].cap = cap;
   e[cnt].cos = cos;
   e[cnt].next = h[u];
   h[u] = cnt++;
   e[cnt].to = u;
   e[cnt].cap = 0;
   e[cnt].cos = -cos;
   e[cnt].next = h[v];
   h[v] = cnt++;
}
bool spfa() {
   queue<int> q;
   memset(pre, -1, sizeof pre);
   memset(vis, 0, sizeof vis);
   memset(dis, 0x3f, sizeof dis);
   dis[s] = 0;
   vis[s] = 1;
   flow[s] = INF;
   q.push(s);
   while (q.size()) {
   	int u = q.front();
   	q.pop();
   	vis[u] = 0;
   	for (int i = h[u]; ~i; i = e[i].next) {
   		int v = e[i].to;
   		if (e[i].cap && dis[v] > dis[u] + e[i].cos) {
   			pre[v] = u;
   			last[v] = i;
   			dis[v] = dis[u] + e[i].cos;
   			flow[v] = min(flow[u], e[i].cap);
   			if (!vis[v]) {
   				q.push(v);
   				vis[v] = 1;
   			}
   		}
   	}
   }
   return pre[t] != -1;
}
void MCMF() {
   while (spfa()) {
   	ans[++k] = ans[k-1] + 1ll*flow[t] * dis[t];
   	int now = t;
   	while (now != s) {
   		e[last[now]].cap -= flow[t];
   		e[last[now] ^ 1].cap += flow[t];
   		now = pre[now];
   	}
   }
}
void solve() {
   scanf("%d %d", &n, &m);
   memset(h, -1, sizeof h);
   memset(ans, 0, sizeof ans);
   cnt = 0;
   k = 0;
// 起点,会点
   s = 0, t = N-2;
   for (int i = 1; i <= b.size(); i++) {//所有机器向汇点连边
   	add(i + n, t, 1, 0);
   }
   MCMF();
   // 固定流量的最小费用
   for (int i = 1; i <= k; i++) {
   	if (i != k) printf("%lld ", ans[i]);
   	else printf("%lld
", ans[i]);
   }
}

字符串

后缀数组

int y[N], x[N], c[N], sa[N], rk[N], height[N] , st[30][N] ;
int get_SA() {
    memset(c, 0, sizeof(c));
    for (int i = 1; i <= n; ++i) ++c[x[i] = s[i]];
    for (int i = 2; i <= m; ++i) c[i] += c[i - 1];
    for (int i = n; i >= 1; --i) sa[c[x[i]]--] = i;
    for (int k = 1; k <= n; k <<= 1) {
        int num = 0;
        for (int i = n - k + 1; i <= n; ++i) y[++num] = i;
        for (int i = 1; i <= n; ++i) if (sa[i] > k) y[++num] = sa[i] - k;
        for (int i = 1; i <= m; ++i) c[i] = 0;
        for (int i = 1; i <= n; ++i) ++c[x[i]];
        for (int i = 2; i <= m; ++i) c[i] += c[i - 1];
        for (int i = n; i >= 1; --i) sa[c[x[y[i]]]--] = y[i], y[i] = 0;
        swap(x, y);
        x[sa[1]] = 1;
        num = 1;
        for (int i = 2; i <= n; ++i)
            x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) ? num : ++num;
        if (num == n) break;
        m = num;

    }
    return 0;
}
int get_height() {
    int k = 0;
    for (int i = 1; i <= n; ++i) rk[sa[i]] = i;
    for (int i = 1; i <= n; ++i) {
        if (rk[i] == 1) continue;
        if (k) --k;
        int j = sa[rk[i] - 1];
        while (j + k <= n && i + k <= n && s[i + k] == s[j + k]) ++k;
        height[rk[i]] = k;
    }
    return 0 ;
}
void build_st() {
    for (int i = 1; i <= n; i++) st[0][i] = height[i];
    for (int k = 1; k <= 19; k++) {
        for (int i = 1; i + (1 << k) - 1 <= n; i++) {
            st[k][i] = min(st[k - 1][i], st[k - 1][i + (1 << k - 1)]);
        }
    }
    return ;
}
int lcp(int x, int y) {
    int l = rk[x], r = rk[y];
    if (l > r) swap(l, r);
    if (l == r) return n - x + 1;
    int t = log2(r - l);
    return min(st[t][l + 1], st[t][r - (1 << t) + 1]);
}
struct node {
  int l , r , sum ;
}t[N * 4];
int tot = 0 ;
void up(int now) {
  t[now].sum = t[t[now].l].sum + t[t[now].r].sum ;
}
void build(int &now , int l , int r) {
  t[now = ++ tot].sum = 0 ;
  if(l == r) return ;
  int mid = l + r >> 1 ;
  build(t[now].l , l , mid) ;
  build(t[now].r , mid + 1 , r) ;
  return ;
}
void update(int &now , int last , int l , int r , int pos) {
  t[now = ++ tot] = t[last] ;
  t[now].sum ++ ;
  if(l == r) return ;
  int mid = l + r >> 1 ;
  if(pos <= mid) update(t[now].l , t[last].l , l , mid , pos) ;
  else update(t[now].r , t[last].r , mid + 1 , r , pos) ;
  return ;
}
int ask(int now , int last , int l , int r , int k) {
  if(l == r) return l ;
  int sum = t[t[now].l].sum - t[t[last].l].sum ;
  int mid = l + r>> 1 ;
  if(sum >= k) return ask(t[now].l , t[last].l , l , mid , k) ;
  else return ask(t[now].r , t[last].r , mid + 1 , r , k - sum) ;
}
int root[N] ;
int work(){
  int q ;
  tot = 0 ;
  scanf("%d%d" , &n , &q) ;
  scanf("%s" , s + 1) ;
  m = 123 ;
  get_SA() ;
  get_height() ;
  build_st() ;
  build(root[0] , 1,  n ) ;
  for(int i = 1; i <= n; i ++ ) update(root[i] , root[i - 1] , 1 , n , sa[i]) ;
  while(q --) {
    int l , r , k ;
    scanf("%d%d%d" , &l , &r , &k) ;
    int len = r - l + 1 ;
    int left = 1 , right = rk[l] ;
    int ans = rk[l] ;
    while(left <= right) {
      int mid = left + right >> 1 ;
      if(lcp(sa[mid] , l) >= len) right = mid - 1 , ans = mid ;
      else left = mid + 1 ;
    }
    int LL = ans ;
    ans = rk[l] ;
    right = n ;
    left = rk[l] ;
    while(left <= right) {
      int mid = left + right >> 1 ;
      if(lcp(sa[mid] , l) >= len) left = mid + 1 , ans = mid ;
      else right = mid - 1 ;
    }
    int RR = ans ;
    if(RR - LL + 1 < k) puts("-1") ;
    else printf("%d
" , ask(root[RR] , root[LL - 1] , 1 , n , k)) ;
  }
  return 0 ;
}

AC自动机

struct Trie{
 int t[N][26] , fail[N] , cnt[N] , in[N] , q[N] , h , tail , tot ;
 void init() {
   tot = 0 ;
   memset(fail , 0 , sizeof fail) ;
   memset(t , 0 , sizeof t) ;
   memset(cnt , 0 , sizeof cnt) ;
   memset(q , 0 , sizeof q) ;
 }
 int ins(char *x) {
   int i = 0 ;
   for(int j = 0 ;x[j] ;j ++ ) {
     int c = x[j] - 'a' ;
     if(!t[i][c]) t[i][c] = ++ tot ;
     i = t[i][c] ;
   }
   return i ;
 }
 void get_fail() {
   h = 1 ,tail = 0 ;
   for(int i = 0 ;i < 26 ;i ++ ) if(t[0][i]) q[++ tail] = t[0][i] ;
   while(h <= tail) {
     int i = q[h ++] ;
     for(int j = 0 ;j < 26 ;j ++ ) {
       if(t[i][j]) {
         fail[t[i][j]] = t[fail[i]][j] ;
         q[++ tail] = t[i][j] ;
       }else {
         t[i][j] = t[fail[i]][j] ;
       }
     }
   }
 }
 void solve() {
   for(int i = tail ;i > 0 ;i --) cnt[fail[q[i]]] += cnt[q[i]] ;
 }
}T;
char x[510][510] ;
char s[N] ;
int id[N] ;
int work()
{
 int n , m , q ;
 scanf("%d" , &n) ;
 T.init() ;
 for(int i = 1; i <= n; i ++ ) {
   scanf("%s" , s) ;
   id[i] = T.ins(s) ;
 }
 T.get_fail() ;
 scanf("%s" , s) ;
 int p = 0 ;
 for(auto x : s)
  p = T.t[p][x - 'a'] , T.cnt[p] ++ ;
 T.solve() ;
 int ans = 0 ;
 for(int i = 1; i <= n ;i ++ )
   ans += T.cnt[id[i]] ;
 cout << ans << endl ;
 return 0 ;
}

字符串最小表示法

int getmin(int *a){
   static int b[12] ;
   for(int i = 0 ;i < 12 ;i ++) b[i] = a[i % 6] ;
   int i = 0 , j = 1 , k ;
   while(i < 6 && j < 6){
        for(k = 0 ;k < 6 && b[j + k] == b[i + k] ; k ++)  ;
        if(k == 6) break ;
        if(b[i + k] > b[j + k]){
              i += k + 1 ;
              if(i == j) i ++ ;
          }
        if(b[i + k] < b[j + k]){
             j += k + 1 ;
             if(i == j) j ++ ;
         }
    }
    k = min(i , j) ;
    for(int i = 0 ; i < 6 ;i ++)
     a[i] = b[i + k] ;
    return 0 ;
}

马拉车算法

void init(int l , int r){
   int k=0;
   str[k++] = '$';
   for(int i=l;i<=r;i++){
       str[k++]='#';
       str[k++]=s[i];
   }
   str[k++]='#';
   len=k;
   str[k] = '' ;
}
int ans = 0 , flag ;
int Manacher(){
 Len[0] = 0;
 int sum = 0;
 mx = 0;
 id = 0 ;
 // cout << str << endl ;
 for(int i=1;i<len;i++){
   if(i < mx) Len[i] = Min(mx - i, Len[2 * id - i]);
   else Len[i] = 1;
   while(str[i - Len[i]]== str[i + Len[i]]) Len[i]++;
   if(Len[i] + i > mx){        // 更新最长的回文串
     mx = Len[i] + i;          // mx是回文串右边一个位置
     id = i;             //id是回文串的中心
     sum = Max(sum, Len[i]);         // sum 是回文串的长度 + 1

   }
   // cout << i << " " << Len[i] << endl ;
   // if(Len[i] == i)  表示前缀是回文的
   //  {
   //    if(ans < Len[i])
   //     ans = Len[i] - 1 , flag = 1 ;
   //  }
   // if(Len[i] + i == len)  表示后缀是回文的
   //  if(ans < Len[i])
   //   ans = Len[i] - 1 , flag = 2 ;
 }
 return sum - 1 ;
}

kmp

void get_next()
{
   for(int i = 2, j = 0 ;i <= n;i ++)
   {
       while(j && p[i] != p[j + 1]) j = nextp[j];
       if(p[i] == p[j + 1]) j ++ ;
       nextp[i] = j ;
   }
}
int main()
{
 // 在s串里面查找
   cin >> s + 1 ;
   m = strlen(s + 1);
   cin >> p + 1 ;
   n = strlen(p + 1) ;
   get_next();
   int x = 0 ;
   for(int i = 1 , j = 0;i <= m;i ++){
       while(j && s[i] != p[j + 1]) j = nextp[j] ;
       if(s[i] == p[j + 1]) j ++ ;
       if(j == n){
         //  cout << i - n << " " ;
           x ++ ;
           j = nextp[j] ;
       }
   }
   cout << x << endl  ;
   return 0;
}

数据结构

字典树

区间内小于某个数的所有数之和
int n , m , root[N * 20] ;
ll a[N] , bin[N] ;
struct node {
 ll sum , l , r ;
}t[N * 40];
void fj(ll x) {
 if(x > 1000000000ll) x = 1000000001ll ;
 for(int i = 0 ;i <= 30 ;i ++ )
  bin[i] = (x >> i) & 1ll ;
}
int tot = 0 ;
void insert(int &now , int last , int id , ll w) {
 t[now = ++ tot] = t[last] ;
 if(id < 0) {
   t[now].sum += w ;
   return ;
 }
 if(!bin[id]) insert(t[now].l , t[last].l , id - 1 , w) ;
 else insert(t[now].r , t[last].r , id - 1 , w) ;
 t[now].sum = t[t[now].l].sum + t[t[now].r].sum ;
}
// 贪心的走
ll ask(int rt , int id) {
 if(id < 0 || !rt) return t[rt].sum ;
 ll res = 0 ;
 if(!bin[id]) res = ask(t[rt].l , id - 1) ;
 else res = t[t[rt].l].sum + ask(t[rt].r , id - 1) ;
 return res ;
}
int work()
{
 scanf("%d%d" , &n , &m) ;
 for(int i = 1; i <= n ;i ++ ) {
   scanf("%d" , &a[i]) ;
   fj(a[i]) ;
   insert(root[i] , root[i - 1] , 30 , a[i]) ;
 }
 for(int i = 1; i <= m ;i ++ ) {
   int l , r ;
   scanf("%d%d" , &l , &r) ;
   ll sum = 1 , last = 0 ;
   while(1) {
     fj(sum) ;
     ll temp = ask(root[r] , 30) - ask(root[l - 1] , 30) ;
     if(temp == last) {
       printf("%lld
" , sum) ;
       break ;
     }
     last = temp , sum = temp + 1 ;
   }
 }
 return 0 ;
}

主席树

主席树求区间小于某个数的个数
int root[N] , tot ;
struct node {
int l , r , sum ;
}t[N];
void build(int &now , int l , int r) {
t[now = ++ tot].sum = 0 ;
if(l == r) return ;
int mid = l + r >> 1 ;
build(t[now].l , l , mid) ;
build(t[now].r , mid + 1 , r) ;
return ;
}
void up(int now) {
t[now].sum = t[t[now].l].sum + t[t[now].r].sum ;
}
void update(int &now , int last , int l , int r , int pos) {
t[now = ++ tot] = t[last] ;
if(l == r) {
  t[now].sum ++ ;
  return ;
}
int mid = l + r >> 1 ;
if(pos <= mid) update(t[now].l , t[last].l , l , mid , pos) ;
else update(t[now].r , t[last].r , mid + 1 , r , pos) ;
up(now) ;
return ;
}
int ask(int now , int last , int l , int r , int k) {
if(!k) return 0 ;
if(r <= k) return  t[now].sum - t[last].sum ;
int mid = l + r >> 1 ;
int ans = 0 ;
if(k <= mid) ans += ask(t[now].l , t[last].l , l , mid , k) ;
else ans += ask(t[now].l , t[last].l , l , mid , k) + ask(t[now].r , t[last].r , mid + 1 , r , k ) ;
return ans ;
}
int ca = 0 ;
int work()
{
int n , m ;
scanf("%d%d" , &n , &m) ;
for(int i = 1; i <= n ;i ++ ) scanf("%d" , &a[i]) , b[i] = a[i] ;
sort(b + 1 , b + n + 1) ;
cnt = unique(b + 1,  b + n + 1) - b - 1 ;
for(int i = 1; i <= n ;i ++ ) a[i] = lower_bound(b + 1 , b + cnt + 1 , a[i]) - b ;
tot = 0 ;
build(root[0] , 1 , cnt) ;
for(int i = 1 ; i <= n ;i ++ )
  update(root[i] , root[i - 1] , 1 , cnt , a[i]) ;
printf("Case #%d:
" , ++ ca) ;
for(int i = 1; i <= m ;i ++ ) {
  int l , r , x , y ;
  scanf("%d%d%d%d" , &l , &r , &x , &y) ;
  y = upper_bound(b + 1 , b + cnt + 1 , y) - b - 1 ;
  x = upper_bound(b + 1 , b + cnt + 1 , x - 1) - b - 1;
  printf("%d
" , ask(root[r] , root[l - 1] , 1 , cnt , y) - ask(root[r] , root[l - 1] , 1 , cnt , x)) ;
}
return 0 ;
}
主席树求区间第k小(静态)
struct Tree {
  int l, r, sum;
} T[MAXN * 40];
vector<int> v ;
int cnt, root[MAXN], a[MAXN];
void Init() 
{
  cnt = 0;
  T[cnt].l = 0;
  T[cnt].r = 0;
  T[cnt].sum = 0;
  root[cnt] = 0;
  v.clear();
}
int getid(int x) 
{ 
   return lower_bound(v.begin(), v.end(), x) - v.begin() + 1; 
}
void Update(int l, int r, int &x, int y, int pos) 
{
  T[++cnt] = T[y], T[cnt].sum++, x = cnt;
  if (l == r) return;
  int mid = (l + r) >> 1;
  if (mid >= pos)
      Update(l, mid, T[x].l, T[y].l, pos);
  else
      Update(mid + 1, r, T[x].r, T[y].r, pos);
}
int Query(int l, int r, int x, int y, int k) 
{
  if (l == r) return l;
  int mid = (l + r) >> 1;
  int sum = T[T[y].l].sum - T[T[x].l].sum;
  if (sum >= k)
      return Query(l, mid, T[x].l, T[y].l, k);
  else
      return Query(mid + 1, r, T[x].r, T[y].r, k - sum);
}
int main() 
{
  Init();
  int n, m;
  scanf("%d%d", &n, &m);
  for (int i = 1; i <= n; i++) 
      scanf("%d", &a[i]),v.push_back(a[i]);
  sort(v.begin(), v.end());
  v.erase(unique(v.begin(), v.end()), v.end());
  for (int i = 1; i <= n; i++)
      Update(1, n, root[i], root[i - 1], getid(a[i]));
  int l, r, k;
  for (int i = 1; i <= m; i++) 
  {
      scanf("%d%d%d", &l, &r, &k);
      printf("%d
", v[Query(1, n, root[l - 1], root[r], k) - 1]);
  }
  return 0;
}
主席树求区间小于某个数所有数的和
struct node {
ll sum ;
int l , r ;
}t[N * 40];
void fj(ll x) {
if(x > 1000000000ll) x = 1000000001ll ;
for(int i = 0 ;i <= 30 ;i ++ )
 bin[i] = (x >> i) & 1ll ;
}
int tot = 0 ;
void insert(int &now , int last , int id , ll w) {
t[now = ++ tot] = t[last] ;
if(id < 0) {
  t[now].sum += w ;
  return ;
}
if(!bin[id]) insert(t[now].l , t[last].l , id - 1 , w) ;
else insert(t[now].r , t[last].r , id - 1 , w) ;
t[now].sum = t[t[now].l].sum + t[t[now].r].sum ;
}
// 贪心的走
ll ask(int rt , int id) {
if(id < 0 || !rt) return t[rt].sum ;
ll res = 0 ;
if(!bin[id]) res = ask(t[rt].l , id - 1) ;
else res = t[t[rt].l].sum + ask(t[rt].r , id - 1) ;
return res ;
}
int work()
{
scanf("%d%d" , &n , &m) ;
for(int i = 1; i <= n ;i ++ ) {
  scanf("%d" , &a[i]) ;
  fj(a[i]) ;
  insert(root[i] , root[i - 1] , 30 , a[i]) ;
}
for(int i = 1; i <= m ;i ++ ) {
  int l , r ;
  scanf("%d%d" , &l , &r) ;
  ll sum = 1 , last = 0 ;
  while(1) {
    fj(sum) ;
    ll temp = ask(root[r] , 30) - ask(root[l - 1] , 30) ;
    if(temp == last) {
      printf("%lld
" , sum) ;
      break ;
    }
    last = temp , sum = temp + 1 ;
  }
}
return 0 ;
}

虚树

void dfs(int u){
   dfn[u] = ++idx;
   deep[u] = deep[fa[u][0]] + 1;
   for(int e : RG[u]){
       int v = U[e] ^ V[e] ^ u;
       if(v == fa[u][0]) continue;
       me[v] = C[e];
       if(u != 1 && me[u] < me[v]) me[v] = me[u];
       fa[v][0] = u;
       dfs(v);
   }
}
int LCA(int u,int v){
   if(deep[u] < deep[v]) swap(u,v);
   int delta = deep[u] - deep[v];
   for(int i = 19;i >= 0;--i){
       if((delta >> i) & 1) u = fa[u][i];
   }
   for(int i = 19;i >= 0;--i){
       if(fa[u][i] != fa[v][i]) u = fa[u][i],v = fa[v][i];
   }
   if(u == v) return u;
   return fa[u][0];
}
bool comp(int a,int b){
   return dfn[a] < dfn[b];
}
void insert(int u){
   if(top == 1) {stk[++top] = u;return;}
   int lca = LCA(u,stk[top]);
   if(lca == stk[top]) {stk[++top] = u;return ;}
   while(top > 1 && dfn[lca] <= dfn[stk[top-1]]){
       VG[stk[top-1]].push_back(stk[top]);
       --top;
   }
   if(lca != stk[top]) {
       VG[lca].push_back(stk[top]);
       stk[top] = lca;
   }
   stk[++top] = u;
}
int idq[maxn],mark[maxn];
ll DP(int u){
   ll cost = 0;
   for(int v : VG[u])
       cost += min(me[v],DP(v));
   VG[u].clear();
   if(mark[u]) return me[u];
   else return cost;
}
int main(){
   init();
   ios::sync_with_stdio(false);
   cin >> n;
   for(int i = 1;i < n;++i){
       cin >> U[i] >> V[i] >> C[i];
       RG[U[i]].push_back(i);
       RG[V[i]].push_back(i);
   }
   dfs(1);
   for(int t = 1;t <= 19;++t) for(int i = 1;i <= n;++i){
       fa[i][t] = fa[fa[i][t-1]][t-1];
   }
   cin >> m;
   for(int i = 0;i < m;++i){
       int sz;
       cin >> sz;
       for(int j = 0;j < sz;++j){
           cin >> idq[j];
           mark[idq[j]] = 1;
       }
       sort(idq,idq+sz,comp);
       top = 0;
       stk[++top] = 1;
       for(int j = 0;j < sz;++j) insert(idq[j]);
       while(top > 0) {
           VG[stk[top-1]].push_back(stk[top]);
           top--;
       }
       cout << DP(1) << endl;
       for(int j = 0;j < sz;++j) VG[idq[j]].clear(),mark[idq[j]] = 0;
       VG[0].clear();
   }
   return 0;
}

线段树

线段树板子乘加
//线段树操作   区间最大值  单点修改  单点查询
//             区间修改  区间查询   最大连续和

#include <iostream>
using namespace std;
const int N = 1e5 + 10 ;
typedef long long ll;
int a[N];
struct node{
  ll muti , add , v;
}tree[4 * N];
int n , m , mod;
void pushdown(int root ,int l,int r){
  int mid = l + r >> 1;
  tree[root * 2].v =(tree[root * 2].v * tree[root].muti + tree[root].add * (mid - l + 1)) % mod;
  tree[root * 2 + 1].v =(tree[root * 2 + 1].v * tree[root].muti + tree[root ].add * (r - mid)) % mod;
  tree[root * 2].muti =(tree[root * 2].muti * tree[root].muti) % mod ;
  tree[root * 2 + 1].muti =(tree[root * 2 + 1].muti * tree[root].muti) % mod ;
  tree[root * 2].add =(tree[root * 2].add * tree[root].muti + tree[root].add) % mod ;
  tree[root * 2 + 1].add =(tree[root * 2 + 1].add * tree[root].muti + tree[root].add) % mod ;
  tree[root].muti = 1 ,tree[root].add = 0;
  return ;
}
void build(int root ,int l,int r){
  tree[root].add = 0,tree[root].muti = 1;
  if(l == r){
  	tree[root].v = a[l] ; return ;
  }
  int mid  = l + r >> 1 ;
  build(root * 2 , l, mid) ,build(root * 2 + 1,mid + 1 ,r );
  tree[root].v = (tree[root * 2].v + tree[root * 2 + 1].v ) % mod;
  return ;

}
void change1(int root ,int treel,int treer ,int x, ll k){//单点修改   将第x 个修改为 k
  tree[root].v += k;
  int mid = treel + treer >> 1;
  if(x > mid) change1(root * 2 + 1,mid + 1,treer , x , k);
  else change1(root * 2 , treel,mid , x , k);
  tree[root].v = (tree[root * 2].v + tree[root * 2 + 1].v) % mod ;
  return ;
}
int query1(int root,int treel,int treer,int x){ // 单点查询   第x个点
  if(treel == treer) return tree[root].v ;
  int mid = treel + treer >> 1;
  if(x <= mid) query1(root * 2 , treel ,mid ,x);
  else query1(root * 2 + 1 ,mid + 1 ,treer ,x) ;
}
void change2(int root,int treel,int treer,int l,int r,ll k){ // 区间修改   乘法   x - y区间乘上 k
  if(l >treer || r < treel) return ;
  if(l <= treel && treer <= r){
  	tree[root].v =(tree[root].v * k) % mod ;
  	tree[root].muti = (tree[root].muti * k) % mod ;
  	tree[root].add = (tree[root].add * k) % mod ;
  	return ;
  }
  pushdown(root,treel,treer);
  int mid = treel + treer >> 1 ;
  change2(root * 2,treel,mid , l ,r ,k);
  change2(root * 2 + 1,mid + 1,treer, l ,r ,k);
  tree[root].v = (tree[root * 2].v + tree[root * 2 + 1].v) % mod ;
  return ;
}
void change3(int root,int treel,int treer,int l,int r,ll k){ // 区间修改  加法  x- y区间加上k
  if(l >treer || r < treel) return ;
  if(l <= treel && treer <= r){
  	tree[root].v =(tree[root].v + k*(treer- treel + 1)) % mod ;
  	tree[root].add = (tree[root].add + k) % mod ;
  	return ;
  }
  pushdown(root,treel,treer);
  int mid = treel + treer >> 1 ;
  change3(root * 2,treel,mid , l ,r ,k);
  change3(root * 2 + 1,mid + 1,treer, l ,r ,k);
  tree[root].v = (tree[root * 2].v + tree[root * 2 + 1].v) % mod ;
  return ;
}

ll query2(int root,int treel,int treer,int l,int r){ // 区间求和  求区间x - y 的和
  if(l >treer || r <treel) return 0;
  if(l <= treel &&treer <= r) return tree[root].v ;
  pushdown(root,treel,treer);
  int mid = treel + treer >> 1;
  return (query2(root * 2 ,treel,mid , l ,r) + query2(root * 2 + 1,mid + 1,treer ,l,r))%mod ;
}
线段树区间最值
void up(int rt){
minx[rt] = max(minx[ls] , minx[rs]) ;
}
void build(int rt , int l , int r){
if(l == r) {
  minx[rt] = a[l] ;
  return ;
}
int mid = l + r >> 1 ;
build(ls , l , mid) ;
build(rs , mid + 1 , r) ;
up(rt) ;
return ;
}
void down(int rt , int l , int r){
if(lazy[rt]) {
  lazy[ls] += lazy[rt] ;
  lazy[rs] += lazy[rt] ;
  minx[ls] += lazy[rt] ;
  minx[rs] += lazy[rt] ;
  minx[rt] = max(minx[ls] , minx[rs]) ;
  lazy[rt] = 0 ;
}
return ;
}
void add(int rt , int l , int r , int ql , int qr , ll k){
if(ql <= l && r <= qr) {
  minx[rt] += k ;
  lazy[rt] += k ;
  return ;
}
down(rt , l , r) ;
int mid = l + r >> 1 ;
if(ql <= mid) add(ls , l , mid , ql , qr , k) ;
if(qr > mid) add(rs , mid + 1 , r , ql , qr , k) ;
up(rt) ;
return ;
}
ll ask(int rt , int l , int r , int ql , int qr){
if(ql <= l && r <= qr) return minx[rt] ;
down(rt , l , r) ;
ll ans = 0 ;
int mid = l + r >> 1 ;
if(ql <= mid) ans = max(ans , ask(ls , l , mid , ql , qr)) ;
if(qr > mid) ans = max(ans , ask(rs , mid + 1 , r , ql , qr)) ;
return ans ;
}
线段树维护矩阵乘法
struct node {
ll a[2][2] ;
} ;
char a[N] ;
node muti(node a , node b){
node res ;
for(int i = 0 ;i < 2; i ++ )
 for(int j = 0 ;j < 2 ;j ++ )
  res.a[i][j] = 0 ;
for(int k = 0 ;k < 2; k ++ )
 for(int i = 0 ;i < 2; i ++ )
  for(int j = 0 ;j < 2; j ++ )
    res.a[i][j] = (res.a[i][j] + a.a[i][k] * b.a[k][j] % mod ) % mod ;
return res ;
}
struct Node {
int l , r , lazy ;
node ans , rans ;
}tr[N];
void up(int rt){
tr[rt].ans = muti(tr[ls].ans , tr[rs].ans) ;
tr[rt].rans = muti(tr[ls].rans , tr[rs].rans) ;
return ;
}
void down(int rt){
if(tr[rt].lazy) {
  swap(tr[ls].ans , tr[ls].rans) ;
  swap(tr[rs].ans , tr[rs].rans) ;
  tr[ls].lazy ^= 1 ;
  tr[rs].lazy ^= 1 ;
  tr[rt].lazy ^= 1 ;
}
return ;
}
void build(int rt , int l , int r){
tr[rt].l = l , tr[rt].r = r ;
tr[rt].lazy = 0 ;
if(l == r) {
  if(a[l] == 'A')  {
    tr[rt].ans.a[0][0] = 1 , tr[rt].ans.a[0][1] = 0 ;
    tr[rt].ans.a[1][0] = 1 , tr[rt].ans.a[1][1] = 1 ;
    tr[rt].rans.a[0][0] = 1 , tr[rt].rans.a[0][1] = 1 ;
    tr[rt].rans.a[1][0] = 0 , tr[rt].rans.a[1][1] = 1 ;
  }else {
    tr[rt].ans.a[0][0] = 1 , tr[rt].ans.a[0][1] = 1 ;
    tr[rt].ans.a[1][0] = 0 , tr[rt].ans.a[1][1] = 1 ;
    tr[rt].rans.a[0][0] = 1 , tr[rt].rans.a[0][1] = 0 ;
    tr[rt].rans.a[1][0] = 1 , tr[rt].rans.a[1][1] = 1 ;
  }
  return ;
}
int mid = l + r >> 1 ;
build(ls , l , mid) ;
build(rs , mid + 1 , r) ;
up(rt) ;
return ;
}
void update(int rt , int l , int r){
if(l <= tr[rt].l && tr[rt].r <= r) {
  tr[rt].lazy ^= 1 ;
  swap(tr[rt].ans , tr[rt].rans) ;
  return ;
}
down(rt) ;
int mid = tr[rt].l + tr[rt].r >> 1 ;
if(l <= mid) update(ls , l , r) ;
if(r > mid) update(rs , l , r) ;
up(rt) ;
return ;
}
node ask(int rt , int l , int r){
if(tr[rt].l >= l && tr[rt].r <= r) return tr[rt].ans ;
down(rt) ;
int mid = tr[rt].l + tr[rt].r >> 1 ;
node ans ;
ans.a[0][0] = 1 , ans.a[0][1] = 0 ;
ans.a[1][0] = 0 , ans.a[1][1] = 1 ;
if(l <= mid) ans = muti(ans , ask(ls , l , r)) ;
if(r > mid) ans = muti(ans , ask(rs , l , r)) ;
up(rt) ;
return ans ;
}
扫描线
const int MAX=20000 ;
int mark[MAX<<2];//记录某个区间的下底边个数
double sum[MAX<<2];//记录某个区间的下底边总长度
double Hash[MAX];//对x进行离散化,否则x为浮点数且很大无法进行线段树
//以横坐标作为线段(区间),对横坐标线段进行扫描
//扫描的作用是每次更新下底边总长度和下底边个数,增加新面积
struct seg{//线段
  double l,r,h;
  int d;
  seg(){}
  seg(double x1,double x2,double H,int c):l(x1),r(x2),h(H),d(c){}
  bool operator<(const seg &a)const{
  	return h<a.h;
  }
}s[MAX];
void Upfather(int n,int left,int right){
  if(mark[n])sum[n]=Hash[right+1]-Hash[left];//表示该区间整个线段长度可以作为底边
  else if(left == right)sum[n]=0;//叶子结点则底边长度为0(区间内线段长度为0)
  else sum[n]=sum[n<<1]+sum[n<<1|1];
}
void Update(int L,int R,int d,int n,int left,int right){
  if(L<=left && right<=R){//该区间是当前扫描线段的一部分,则该区间下底边总长以及上下底边个数差更新
  	mark[n]+=d;//更新底边相差差个数
  	Upfather(n,left,right);//更新底边长
  	return;
  }
  int mid=left+right>>1;
  if(L<=mid)Update(L,R,d,n<<1,left,mid);
  if(R>mid)Update(L,R,d,n<<1|1,mid+1,right);
  Upfather(n,left,right);
}
int search(double key,double* x,int n){
  int left=0,right=n-1;
  while(left<=right){
  	int mid=left+right>>1;
  	if(x[mid] == key)return mid;
  	if(x[mid]>key)right=mid-1;
  	else left=mid+1;
  }
  return -1;
}
int main(){
  int n,num=0;
  double x1,x2,y1,y2;
  while(cin>>n,n){
  	int k=0;
  	for(int i=0;i<n;++i){
  		cin>>x1>>y1>>x2>>y2;
  		Hash[k]=x1;
  		s[k++]=seg(x1,x2,y1,1);
  		Hash[k]=x2;
  		s[k++]=seg(x1,x2,y2,-1);
  	}
  	sort(Hash,Hash+k);
  	sort(s,s+k);
  	int m=1;
  	for(int i=1;i<k;++i)//去重复端点
  	    if(Hash[i] != Hash[i-1])Hash[m++]=Hash[i];
      double ans=0;
      //memset(mark,0,sizeof mark);
      //memset(sum,0,sizeof sum);如果下面是i<k-1则要初始化,因为如果对第k-1条线段扫描时会使得mark,sum为0才不用初始化的
  	for(int i=0;i<k;++i){//扫描线段
  		int L=search(s[i].l,Hash,m);
  		int R=search(s[i].r,Hash,m)-1;
  		Update(L,R,s[i].d,1,0,m-1);//扫描线段时更新底边长度和底边相差个数
  		ans+=sum[1]*(s[i+1].h-s[i].h);//新增加面积
  	}
  	printf("%.0lf
",ans);
  }
puts("*") ;
  return 0;
}
/*
这里注意下扫描线段时r-1:int R=search(s[i].l,Hash,m)-1;
计算底边长时r+1:if(mark[n])sum[n]=Hash[right+1]-Hash[left];
解释:假设现在有一个线段左端点是l=0,右端点是r=m-1
则我们去更新的时候,会算到sum[1]=Hash[mid]-Hash[left]+Hash[right]-Hash[mid+1]
这样的到的底边长sum是错误的,why?因为少算了mid~mid+1的距离,由于我们这利用了
离散化且区间表示线段,所以mid~mid+1之间是有长度的,比如Hash[3]=1.2,Hash[4]=5.6,mid=3
所以这里用r-1,r+1就很好理解了
*/
线段树维护hash
const int N = 1e6 + 10 , INF = 0x3f3f3f3f , p = 1e9 + 7 , mod = 65536 ;
ll pw[N << 2] , hash1[N << 2] , hash2[N << 2] , sum[N << 2] , PW[N] ;
int a[N] ;
void push_up(int rt) {
 sum[rt] = (sum[ls] + sum[rs]) % mod ;
 hash1[rt] = (hash1[ls] * pw[rs] % p + hash1[rs]) % p ;
 hash2[rt] = (hash2[rs] * pw[ls] % p + hash2[ls]) % p ;
 pw[rt] = pw[ls] * pw[rs] % p ;
 return ;
}
void build(int rt , int l , int r) {
 if(l == r) {
   pw[rt] = 19260817 ;
   hash1[rt] = hash2[rt] = sum[rt] = a[l] ;
   return ;
 }
 int mid = l + r >> 1 ;
 build(ls , l , mid) ;
 build(rs , mid + 1 , r) ;
 push_up(rt) ;
}
void update(int rt , int l , int r , int p) {
 if(l == r) {
   hash1[rt] = hash2[rt] = sum[rt] = a[l] ;
   return  ;
 }
 int mid = l + r >> 1 ;
 if(p <= mid) update(ls,  l , mid , p) ;
 else update(rs , mid + 1 , r , p) ;
 push_up(rt) ;
}
ll ask1(int rt , int l , int r , int ql , int qr) {
 if(ql <= l && r <= qr) return sum[rt] ;
 int mid = l + r >> 1 , ans = 0 ;
 if(ql <= mid) ans = (ans + ask1(ls , l , mid , ql , qr)) % mod ;
 if(qr > mid) ans = (ans + ask1(rs , mid + 1 , r  , ql , qr)) % mod ;
 return ans ;
}
ll ask2(int rt , int l , int r , int ql , int qr) {
 if(ql <= l && r <= qr)
   return hash1[rt] ;
 int mid = l + r >> 1 ;
 ll ans = 0 ;
 if(ql <= mid) ans = (ans + ask2(ls , l , mid , ql , qr) * PW[mid < min(qr , r) ? min(qr , r) - mid : 0]) % p ;
 if(qr > mid) ans = (ans + ask2(rs , mid + 1 , r , ql , qr)) % p ;
 return ans ;
}
ll ask3(int rt , int l , int r , int ql , int qr) {
 if(ql <= l && r <= qr) return hash2[rt] ;
 int mid = l + r >> 1 ;
 ll ans = 0 ;
 if(ql <= mid)  ans = (ans + ask3(ls , l , mid , ql , qr)) % p ;
 if(qr > mid) ans = (ans + ask3(rs , mid + 1 , r , ql , qr) * PW[max(l , ql) <= mid ? mid - max(l , ql) + 1 : 0]) % p ;
 return ans ;
}
// 1 a[l , r] ++
// 2 [x , x + L - 1] == [y , y + L - 1]
int main()
{
 int n , q ;
 memset(pw , 1 , sizeof pw) ;
 scanf("%d%d" , &n , &q) ;
 PW[0] = 1 ;
 for(int i = 1; i <= n ;i ++ )
  PW[i] = PW[i - 1] * 19260817 % p ;
 for(int i = 1; i <= n ;i ++ ) scanf("%d" , &a[i]) ;
 for(int i = n ;i >= 2; i -- ) {
   a[i] -= a[i - 1] ;
   if(a[i] < 0) a[i] += mod ;
 }
 build(1 , 1 , n) ;
 while(q --) {
   int op ;
   scanf("%d" , &op) ;
   if(op == 1) {
     int l , r ;
     scanf("%d%d" , &l , &r) ;
     a[l] = (a[l] + 1) % mod ;
     update(1 , 1 , n , l) ;
     if(r != n) {
       a[r + 1] -- ;
       if(a[r + 1] < 0) a[r + 1] += mod ;
       update(1 , 1 , n , r + 1) ;
     }
   }else {
     int x , y , L ;
     scanf("%d%d%d" , &x , &y , &L) ;
     if(x > y) swap(x , y) ;
     if(x == y) puts("yes") ;
     else if(ask1(1 , 1 , n , x + 1 , y) != 0) puts("no") ;
     else if(ask2(1 , 1 , n , x + 1 , x + L - 1) != ask2(1 , 1 , n , y + 1 , y + L - 1))
               puts("no") ;
     else if(ask3(1 , 1 , n , x + 1 , x + L - 1) != ask3(1 , 1 , n , y + 1 , y + L - 1))
                puts("no") ;
     else puts("yes") ;
    }
 }
 return 0 ;
}

树hash

void get(){
 for(int i = 2; i < N ;i ++ ) {
   if(!vis[i]) prime[++ tot] = i ;
   for(int j = 1; j <= tot && i * prime[j] < N ;j ++ ) {
     vis[i * prime[j]] = 1 ;
     if(i % prime[j] == 0) break ;
   }
 }
}
ll f[N] ;
void dfs2(int u , int fa , int rt) {
 sz[u] = 1 , f[u] = 1;
 for(auto x : v[u]) {
   if(x == fa || x == rt) continue ;
   dfs2(x , u , rt) ;
   sz[u] += sz[x] ;
   f[u] += 1ll * prime[sz[x]] * f[x] ;
 }
}

矩阵树(矩阵树定理主要用于图的生成树计数)

//f[i][i] 存i点的度数
//f[i][j] 存i点到j点的边数的相反数
//ans为图的生成树数量
void add(int u,int v){
   f[u][u]++;f[v][v]++;
   f[u][v]--;f[v][u]--;
}
int u[N] , v[N] , w[N];
ll gauss () {// 生成树的数量
   ll ans = 1 ;
   for (int i = 1; i < n; i ++) {
       for (int j = i + 1; j < n; j ++) {
           while (f[j][i]) {
               ll t = f[i][i] / f[j][i] ;
               for (int k = i; k < n; k ++)
                   f[i][k] = (f[i][k] - t * f[j][k] + mod) % mod ;
               swap(f[i], f[j]) ;
               ans = -ans ;
           }
       }
       ans = (ans * f[i][i]) % mod ;
   }
   return (ans + mod) % mod ;
}

树上启发式合并

统计当前子树内最大颜色点数和
/*
1. CF600E - Lomsat gelral
题意
N个节点以点1为根的树,每一个节点有一个颜色color[i],对于一个以u为根的子树来说,
他的子树中的节点有多种颜色,现在求出出现次数最多的颜色(可能有多个颜色出现次数相同),并将出现次数求和
输出以所有点的答案
分析
以点1为根,我们需要保存的信息为当前点子树中颜色出现次数,并且在统计答案的时候找到颜色最多的
这里我们可以用一个桶cnt[i]来记录颜色ii出现的次数,然后用mx来记录当前次数最多的颜色,sum记录次数最多的颜色的次数之和
这样当某种颜色出现次数cnt>mx的时候,我们将mx更新,
并且sum=cnt (为什么不是加上答案呢,因为我们最大值已经更新了,所以实际上是sum=0, sum = sum + cnt)
当cnt=mx的时候,mx不必更新,sum+=cnt
当cnt<mx的时候,啥都不用做
*/
void dfs(int u , int fa)//轻重链划分
{
size[u] = 1 ;
for(auto x : v[u])
{
  if(x == fa) continue ;
  dfs(x, u) ;
  size[u] += size[x] ;
  if(!son[u] || size[x] > size[son[u]])
   son[u] = x ;
}
}
void upd(int u , int fa , int k) //将信息加入/撤回
{
//k = 1的时候是加上信息,k = -1的时候是撤回信息
// 记录信息
cnt[colour[u]] += k ;
if(k == 1 && cnt[colour[u]] >= mx) {
   if(cnt[colour[u]] > mx) mx = cnt[colour[u]] , sum = 0 ;
   sum += colour[u] ;
 }
for(auto x : v[u])
 if(x != fa && !vis[x]) upd(x , u , k) ;

}
void dsu(int u , int fa , int keep)//u为当前点, fa为父节点, keep为是否保留信息
{
 for(auto x : v[u]) //先搜我们的轻儿子,过程中不保留信息
  if(x != fa && x != son[u]) dsu(x , u , 0) ;
 if(son[u]) dsu(son[u] , u  , 1) , vis[son[u]] = 1 ;
 upd(u , fa , 1) ;
 // 统计答案
 ans[u] = sum ;
 if(son[u]) vis[son[u]] = 0 ;
 if(!keep) upd(u , fa , -1) , mx = 0 , sum = 0; /*  如果信息不保留,那我们就撤回        */
}
统计当前字数内两点之间距离为k的点对
void dfs(int u , int f){
deep[u] = deep[f] + 1 ;
fa[u] = f ;
for(auto x : v[u]){
   if(x != f) {
      dfs(x , u) ;
      size[u] += size[x] ;
      if(!son[u] || size[x] > size[son[u]])
       son[u] = x ;
    }
 }
}
void calc(int u , int keep){
num[deep[u]] += keep ;
sum[deep[u]] += keep * a[u] ;
for(auto x : v[u]) {
  if(x == fa[u] || x == nowson) continue ;
  calc(x , keep) ;
}
}
void query(int u , int lca){
int d = k + 2 * deep[lca] - deep[u] ;
if(d > 0){
  ans[lca] += sum[d] ;
  ans[lca] += num[d] * a[u] ;
}
for(auto x : v[u]){
    if(x == fa[u]) continue ;
    query(x , lca) ;
}
}
void dsu(int u , int fa , int keep){
for(auto x : v[u]){
  if(x == fa || x == son[u]) continue ;
  dsu(x , u , 0) ;
}
if(son[u]) dsu(son[u] , u , 1) , nowson = son[u] ;
for(auto x : v[u]){
   if(x == fa || x == nowson)  continue ;
   query(x , u) ;
   calc(x , 1) ;
 }
 num[deep[u]] += 1 ;
 sum[deep[u]] += a[u] ;
 nowson = 0 ;
 if(!keep) calc(u , -1) ;
}

数论

中国剩余定理

ll exgcd(ll a , ll b , ll &x , ll &y){
  if(b == 0){
   	x = 1 , y = 0 ;
   	return a ;
   }
   ll t = exgcd(b , a % b , y , x) ;
   y -= a / b * x ;
   return t ;
}
ll inv(ll a , ll b){
  ll x , y ;
  ll t = exgcd(a , b , x , y) ;
  while(x < 0) x += b ;
  return x ;
}
ll x[N] , m[N] ;
inline ll CRT(){
for(int i = 1; i <= 4 ;i ++ ) m[i] = prime[i] ;
ll M = 1, ans = 0;
for (int i = 1 ; i <= 4; i++)
  M *= m[i];
for (int i = 1; i <= 4; i++)
  ans = (ans + x[i] * (M / m[i]) % M * inv(M / m[i], m[i]) % M) % M;
return ans ;
}

求n以内的素数个数

#include<cmath>
#include<cstdio>
#include<iostream>
#define IL inline
#define RG register
using namespace std;
typedef long long LL;
const int N=5000005;
const int M=7;
const int PM=2*3*5*7*11*13*17;
int p[N],pi[N];
int phi[PM+1][M+1],sz[M+1];
LL n;
bool f[N];
IL void getprime(){
  for(RG int i=2;i<N;i++){
      if(!f[i])
          p[++p[0]]=i;
      pi[i]=p[0];
      for(RG int j=1;p[j]*i<N;j++){
          f[p[j]*i]=1;
          if(i%p[j]==0)
              break;
      }
  }
}
IL void init(){
  getprime();
  sz[0]=1;
  for(RG int i=0;i<=PM;i++)
      phi[i][0]=i;
  for(RG int i=1;i<=M;i++){
      sz[i]=p[i]*sz[i-1];
      for(RG int j=1;j<=PM;j++)
          phi[j][i]=phi[j][i-1]-phi[j/p[i]][i-1];
  }
}
IL int sqrt2(LL x){
  LL r=(LL)sqrt(x-0.1);
  while(r*r<=x) r++;
  return (int)(r-1);
}
IL int sqrt3(LL x){
  LL r=(LL)cbrt(x-0.1);
  while(r*r*r<=x) r++;
  return (int)(r-1);
}
IL LL getphi(LL x,int s){
  if(s==0) return x;
  if(s<=M) return phi[x%sz[s]][s]+(x/sz[s])*phi[sz[s]][s];
  if(x<=p[s]*p[s]*p[s]&&x<N){
      int s2x=pi[sqrt2(x)];
      LL ans=pi[x]-(s2x+s-2)*(s2x-s+1)/2;
      for(RG int i=s+1;i<=s2x;i++)
          ans+=pi[x/p[i]];
      return ans;
  }
  return getphi(x,s-1)-getphi(x/p[s],s-1);
}
IL LL getpi(LL x){
  if(x<N) return pi[x];
  LL ans=getphi(x,pi[sqrt3(3)])+pi[sqrt3(x)]-1;
  for(RG int i=pi[sqrt3(x)]+1,ed=pi[sqrt2(x)];i<=ed;i++)
      ans-=getpi(x/p[i])-i+1;
  return ans;
}
LL MeiLeh(LL x){
  if(x<N) return pi[x];
  int a=(int)MeiLeh(sqrt2(sqrt2(x)));
  int b=(int)MeiLeh(sqrt2(x));
  int c=(int)MeiLeh(sqrt3(x));
  LL sum=getphi(x,a)+(LL)(b+a-2)*(b-a+1)/2;
  for(int i=a+1;i<=b;i++){
      LL w=x/p[i];
      sum-=MeiLeh(w);
      if(i>c) continue;
      LL lim=MeiLeh(sqrt2(w));
      for(int j=i;j<=lim;j++)
          sum-=MeiLeh(w/p[j])-(j-1);
  }
  return sum;
}

Miller_Rabin

#define me(x,y) memset(x,y,sizeof x)
#define MIN(x,y) x < y ? x : y
#define MAX(x,y) x > y ? x : y
typedef long long ll;
const int maxn = 1e5+10;
const double INF = 0x3f3f3f3f;
const int MOD = 1e6;
const double eps = 1e-06;
ll Quick_Multiply(ll a,ll b,ll p){  // a*b%p
  ll ans = 0;
  a %= p;
  b %= p;
  if(b < 0) a = -a,b = -b;
  while(b){
      if(b&1) ans = (ans+a)%p;
      b >>= 1;
      a = (a+a)%p;
  }
  ans = (ans+p)%p;
  return ans;
}
ll Quick_Pow(ll a,ll b,ll p){   //a^b%p
  ll ans = 1;
  while(b){
      if(b&1) ans = Quick_Multiply(ans,a,p)%p;
      b >>= 1;
      a = Quick_Multiply(a,a,p)%p;
  }
  return ans;
}
bool Miller_Rabin(ll n){    //Miller_Rabin
  ll i,j,a,x,y,t,u,s = 10;
  if(n == 2 || n == 3) return true;
  if(n < 2 || !(n&1)) return false;
  for(t = 0,u = n-1;!(u&1); t++,u>>=1);   //n-1 = u*2^t
  for(i = 0; i < s; i++){
      a = rand()%(n-1)-1;
      x = Quick_Pow(a,u,n);   //a^u
      for(j = 0; j < t; j++){
          y = Quick_Multiply(x,x,n);  //x^2
          if(y == 1 && x != 1 && x != n-1) return false;  //����̽��
          x = y;
      }
      if(x != 1) return false;    //��������
  }
  return true;
}

Pollard_rho

ll factor[maxn];
int tot;
ll muti_mod(ll a,ll b,ll c){    //����(a*b) mod c,a,b,c<2^63
  a%=c , b%=c;
  ll ret=0;
  while (b){
      if (b&1){
          ret+=a;
          if (ret>=c) ret-=c;
      }
      a<<=1;
      if (a>=c) a-=c;
      b>>=1;
  }
  return ret;
}
ll pow_mod(ll x,ll n,ll mod){  //����x^n mod c ,�ǵݹ���
  if (n==1) return x%mod;
  int bit[64],k=0;
  while (n){
      bit[k++]=n&1;
      n>>=1;
  }
  ll ret=1;
  for (k=k-1;k>=0;k--){
      ret=muti_mod(ret,ret,mod);
      if (bit[k]==1) ret=muti_mod(ret,x,mod);
  }
  return ret;
}
bool check(ll a,ll n,ll x,ll t){   //��aΪ����n-1=x*2^t������n�Dz��Ǻ���
  ll ret=pow_mod(a,x,n),last=ret;
  for (int i=1;i<=t;i++){
      ret=muti_mod(ret,ret,n);
      if (ret==1 && last!=1 && last!=n-1) return 1;
      last=ret;
  }
  if (ret!=1) return 1;
  return 0;
}
bool Miller_Rabin(ll n){
  ll x=n-1,t=0;
  while ((x&1)==0) x>>=1,t++;
  bool flag=1;
  if (t>=1 && (x&1)==1){
      for (int k=0;k<S;k++){
          ll a=rand()%(n-1)+1;
          if (check(a,n,x,t)) {flag=1;break;}
          flag=0;
      }
  }
  if (!flag || n==2) return 0;
  return 1;
}
ll gcd(ll a,ll b){
  if (a==0) return 1;
  if (a<0) return gcd(-a,b);
  while (b){
      ll t=a%b; a=b; b=t;
  }
  return a;
}
ll Pollard_rho(ll x,ll c){
  ll i=1,x0=rand()%x,y=x0,k=2;
  while (1){
      i++;
      x0=(muti_mod(x0,x0,x)+c)%x;
      ll d=gcd(y-x0,x);
      if (d!=1 && d!=x){
          return d;
      }
      if (y==x0) return x;
      if (i==k){
          y=x0;
          k+=k;
      }
  }
}
void findfac(ll n){           //�ݹ������������ֽ�N
  if (!Miller_Rabin(n)){
      factor[tot++] = n;
      return;
  }
  ll p=n;
  while (p>=n) p=Pollard_rho(p,rand() % (n-1) +1);
  findfac(p);
  findfac(n/p);
}
int idx = 0 ;
struct node
{
  ll val , num ;
  node() {}
  node(ll val , ll num) : val(val) , num(num) {} 
  bool operator<(const node &a) const 
  {
  	val < a.val ;
  }
}fac[maxn];
void solve(ll n)
{
  if (!Miller_Rabin(n)) printf("Prime
");
  else{
          tot = 0;
          findfac(n);
          sort(factor , factor + tot) ;
          idx = 0 ;
          for(int i = 0 ; i < tot ;i ++)
           {
           	if(factor[i] != fac[idx].val) 
           	 fac[++ idx] = {factor[i] , 1};
           	else 
           	 fac[idx].num ++ ;
  		 }
      }
}
int main(){
  srand(time(NULL));
  int t;
  scanf("%d",&t);
  while (t--){
      ll n;
      scanf("%I64d",&n);
  	solve(n) ;
      for(int i = 1; i <= idx ;i ++)
       cout << fac[i].val << " " << fac[i].num << endl ;
  }
}

min25筛

ll k;
ll check(ll v, ll n, ll ndr, ll nv) {
  return v >= ndr ? (n / v - 1) : (nv - v);
}
// ll S[10000000];
// ll V[10000000];
ll primenum(ll n) // O(n^(3/4))
{
ll r = (ll)sqrt(n);
ll ndr = n / r;
assert(r*r <= n && (r+1)*(r+1) > n);
ll nv = r + ndr - 1;
std::vector<ll> S(nv+1);
std::vector<ll> V(nv+1);
for(ll i=0;i<r;i++) 
  V[i] = n / (i+1);
for(ll i=r;i<nv;i++) 
  V[i] = V[i-1] - 1;
for(ll i = 0;i<nv;i++) 
  S[i] = V[i] - 1; //求素数个数
for(ll p=2;p<=r;p++) {
  if(S[nv-p] > S[nv-p+1]) {
    ll sp = S[nv-p+1]; // sum of primes smaller than p
    ll p2 = p*p;
    for(ll i=0;i<nv;i++) {
      if(V[i] >= p2) {
        S[i] -= 1LL  * (S[check(V[i] / p, n, ndr, nv)] - sp);// //求素数个数
      }
      else break;
    }
  }
}
return S[0];
}
ll primesum(ll n) // O(n^(3/4)){
ll r = (ll)sqrt(n);
ll ndr = n / r;
assert(r*r <= n && (r+1)*(r+1) > n);
ll nv = r + ndr - 1;
std::vector<ll> S(nv+1);
std::vector<ll> V(nv+1);
for(ll i=0;i<r;i++) 
  V[i] = n / (i+1);
for(ll i=r;i<nv;i++) 
  V[i] = V[i-1] - 1;
for(ll i = 0;i<nv;i++) 
  S[i] = V[i] * ( V[i] + 1) / 2 - 1; //求素数和
for(ll p=2;p<=r;p++) { // p is prime
  if(S[nv-p] > S[nv-p+1]) {
    ll sp = S[nv-p+1]; // sum of primes smaller than p
    ll p2 = p*p;
    for(ll i=0;i<nv;i++) 
      if(V[i] >= p2) 
        S[i] -= p* (S[check(V[i] / p, n, ndr, nv)] - sp); //求素数和
      else break;
  }
}
return S[0];
}

ST表

void solve(){
for (int i=1;i<=n;i++) a[i][0]=r[i];
   for (int l=1;(1<<l)<=n;l++)
       for (int i=1;i+(1<<l)-1<=n;i++)
           a[i][l]=min(a[i][l-1],a[i+(1<<(l-1))][l-1]);
}
int get(int x , int y){
int l=(int)log2(y-x+1);
return min(a[x][l],a[y-(1<<l)+1][l]);
}

二次剩余

const int mod=998244353;
template<typename T>
inline int pow(int x,T y)
{
  rg int res=1;x%=mod;
  for(;y;y>>=1,x=(ll)x*x%mod)if(y&1)res=(ll)res*x%mod;
  return res;
}
inline int Quadratic_residue(const int a)
{
  if(a==0)return 0;
  int b=(rand()<<14^rand())%mod;
  while(pow(b,(mod-1)>>1)!=mod-1)b=(rand()<<14^rand())%mod;
  int s=mod-1,t=0,x,inv=pow(a,mod-2),f=1;
  while(!(s&1))s>>=1,t++,f<<=1;
  t--,x=pow(a,(s+1)>>1),f>>=1;
  while(t)
  {
  	f>>=1;
  	if(pow((int)((ll)inv*x%mod*x%mod),f)!=1)x=(ll)x*pow(b,s)%mod;
  	t--,s<<=1;
  }
  return min(x,mod-x);
}

高精度

vector<int> add(vector<int> A,vector<int> B){
  vector<int> C;
  int t=0;
  for(int i=0;i<A.size()||i<B.size();i++) {
      if(i<A.size()) t+=A[i];
      if(i<B.size()) t+=B[i];
      C.push_back(t%10);
      t/=10;
  }
  if(t)
      C.push_back(1);
  return C;
}
vector<int> muti(vector<int> A,int b){
  vector<int> C;
  int t=0;
  for(int i=0;i<A.size()||t;i++){
      if(i<A.size()) t+=A[i]*b;
      C.push_back(t%10);
      t/=10;
  }
  return C;
}
bool cmp(vector<int> A,vector<int> B){
  if(A.size()!=B.size())  return A.size()>B.size();
  for(int i=A.size();i>=0;i--)
      if(A[i]!=B[i])
          return A[i]>B[i];
  return true;
}
vector<int> div(vector<int> A, int b, int &r){
  vector<int> C;
  r = 0;
  for (int i = A.size() - 1; i >= 0; i -- ) {
      r = r * 10 + A[i];
      C.push_back(r / b);
      r %= b;
  }
  reverse(C.begin(), C.end());
  while (C.size() > 1 && C.back() == 0) C.pop_back();
  return C;
}
vector<int> sub(vector<int> A,vector<int> B){
  vector<int> C;
  int t=0;
  for(int i=0;i<A.size();i++){
      t=A[i]-t;
      if(i<B.size()) t-=B[i];
      C.push_back((t+10)%10);
      if(t<0) t=1;
      else t=0;
  }
  while(C.size()>1&&C.back()==0) C.pop_back();
  return C;
}
void print(vector<int> a){
for(int i = a.size() - 1; i >= 0 ;i --) cout << a[i]  ;
puts("") ;
return ;
}

高精度组合数学

void get_prime(int n){
  for(int i = 2;i <= n;i ++) {
       if(!st[i]) prime[tot ++] = i ;
       for(int j = 0; j < tot && i * prime[j] <= n ;j ++){
            st[i * prime[j]] = true ;
            if(i % prime[j] == 0) break ;
        }
   }
   return ;
}
int get(int a , int p){
  int sum = 0 ;
  while(a){
       sum += a / p ;
       a /= p ;
  }
  return sum ;
}
vector<int> muti(vector<int> a , int b){
  int t = 0 ;
  vector<int> res ;
  for(int i = 0;i < a.size() ;i ++){
      t += a[i] * b ;
      res.push_back(t % 10) ;
      t /= 10 ;
  }
  while(t){
      res.push_back(t % 10) ;
      t /= 10 ;
  }
  return res ;
}
int main(){
  int a , b ;
  cin >> a >>  b ;
  get_prime(a);
  for(int i = 0; i < tot ;i ++){
       int p = prime[i] ;
       sum[i] = get(a,p) - get(b,p) - get(a-b , p);
   }
   vector<int> res; 
   res.push_back(1);
   for(int i = 0;i < tot ; i ++)
    for(int j = 0; j < sum[i] ;j ++)
     res = muti(res, prime[i]);
   for(int i = res.size() - 1;i >= 0;i --)
    cout << res[i]  ;
   cout << endl ;
  return 0;
}

高斯消元

#define D double
D a[maxn][maxn];
int n;
int main(){
  scanf("%d",&n);
  for(re int i=1;i<=n;++i){
  	for(re int j=1;j<=n+1;++j){
  		scanf("%lf",&a[i][j]);
  	}
  }
  for(re int i=1;i<=n;++i)//枚举列(项){
  	re int max=i;
  	for(re int j=i+1;j<=n;++j)//选出该列最大系数
  		if(fabs(a[j][i])>fabs(a[max][i]))
          //fabs是取浮点数的绝对值的函数
  			max=j;
  	for(re int j=1;j<=n+1;++j)//交换
  		swap(a[i][j],a[max][j]);
  	if(!a[i][i])//最大值等于0则说明该列都为0,肯定无解{
  		puts("No Solution");
  		return 0;
  	}
  	for(re int j=1;j<=n;++j)//每一项都减去一个数(就是小学加减消元){
  		if(j!=i){
  			re D temp=a[j][i]/a[i][i];
  			for(re int k=i+1;k<=n+1;++k){
  				a[j][k]-=a[i][k]*temp;
                  //a[j][k]-=a[j][i]*a[i][k]/a[i][i];
  			}
  		}
  	}
  }
  //上述操作结束后,矩阵会变成这样
  /*
  k1*a=e1
  k2*b=e2
  k3*c=e3
  k4*d=e4
  */
  //所以输出的结果要记得除以该项系数,消去常数
  for(re int i=1;i<=n;++i)
  {
  	printf("%.2lf
",a[i][n+1]/a[i][i]);
  }
  return 0;
}

康托展开

#include <bits/stdc++.h>
using namespace std ;
//返回数组a中当下顺序的康拖映射
typedef unsigned long long ll ;
ll b[30] ;
//对前 10 个自然数(0 ~ 9)的阶乘存入表
//以免去对其额外的计算
ll fact[22] ;
/**
* @brief 康拓展开
*
* @param[in] permutation 输入的一个全排列
* @param[out] num 输入的康拓映射,即是第几个全排列
*/
ll contor(vector<ll> permutation) {
  ll num = 0;
  ll len = permutation.size();
  for (ll i = 0; i < len; ++i) {
      ll cnt = 0; // 在 i 之后,比 i 还小的有几个
      for (ll j = i + 1; j < len; ++j)
          if (permutation[i] > permutation[j]) ++cnt;
      num += cnt * fact[len - i - 1];
  }
  return num + 1;
}
//对前 10 个自然数(0 ~ 9)的阶乘存入表
//以免去对其额外的计算
/**
* @brief 逆康拓展开
*
* @param[in] bits 给定全排列的使用数字个数
* @param[in] num 给定全排列的次位
* @param[out] permutation 输出对应的全排列
*/
vector<ll> revContor(ll bits, ll num) {
  num = num - 1; //有 num - 1 个排列比目标序列要小
  vector<bool> vis(bits + 1, false);
  vector<ll> permutation(bits, -1);

  ll n, residue = num;
  for (ll i = 0; i < bits; ++i) {
      n = residue / (fact[bits - i - 1]);
      residue = residue % (fact[bits - i - 1]);

      for (ll j = 1; j <= bits; ++j) {
          if (!vis[j] && !(n--)) {
              vis[j] = true;
              permutation[i] = j;
              break;
          }
      }
  }
  return permutation;
}
int main()
{
int n , m ;
cin >> n >> m ;
fact[0] = 1;
for(ll i = 1; i <= n ;i ++)
 fact[i] = fact[i - 1] * i ;
for(int i = 1; i <= m ;i ++)
 {
   char s[2] ;
   cin >> s ;
   if(s[0] == 'P') // 求第x大的字典序
    {
      ll x ;cin >> x ;
      vector<ll> t = revContor(n , x) ;
      for(auto xx : t)
       cout << xx << " " ;
      puts("") ;
    }
    else      // 求字典序第几大
     {
       vector<ll> b ;
       for(ll i = 1 , x ; i <= n ;i ++) cin >> x , b.push_back(x) ;
       cout << contor(b) << endl ;
     }
 }
return 0 ;
}

扩展欧几里得

ll exgcd(ll a , ll b , ll &x , ll &y){
  if(b == 0){
       x = 1 , y = 0 ;
       return a ;
   }
   ll d = exgcd(b , a % b , y , x ) ;
   y -= (a / b) * x ;
   return d ;
}

扩展欧几里得求正整数

ll exgcd(ll a,ll b,ll &x,ll &y){
  if(b==0){
  	x=1;
  	y=0;
  	return a;
  }
  ll q=exgcd(b,a%b,x,y);
  ll t=x;
  x=y;
  y=t-a/b*y;
  return q;
}
ll gcd(ll a , ll b)
{
return b == 0 ? a : gcd(b , a % b) ;
}
ll tx , ty , tz ;
// 求正整数
void get(ll a , ll b , ll d)
{
  ll x , y ;
  int md=exgcd(a,b,x,y);
  a/=md,b/=md,d/=md;
  int x1=x*d;
x1=(x1%b+b)%b;
ll y1=(d-a*x1)/b;
y1=abs(y1);
ll y2=y*d;
y2=(y2%a+a)%a;
int x2=(d-b*y2)/a;
x2=abs(x2);
if(x1+y1<x2+y2) tx = x1 , ty = y1 ;
else tx = x2 , ty = y2 ;
}

三维差分

for(int i = 1; i <= m ;i ++ ) {
int a , b , c , d , e , f ;
// a <= x <= d , b <= y <= e , c <= z <= f
cin >> a >> b >> c >> d >> e >> f ;
sum[a][b][c] ++ ;
sum[a][e + 1][c] -- ;
sum[d + 1][b][c] -- ;
sum[a][b][f + 1] -- ;
sum[d + 1][b][f + 1] ++ ;
sum[a][e + 1][f + 1] ++ ;
sum[d + 1][e + 1][c] ++ ;
sum[d + 1][e + 1][f + 1] -- ;
}
for(int i = 1; i <= n ;i ++ ) {
for(int j = 1; j <= n ;j ++ ) {
  for(int k = 1; k <= n ;k ++ ) {
    sum[i][j][k] += sum[i - 1][j][k] + sum[i][j - 1][k] + sum[i][j][k - 1] + sum[i - 1][j - 1][k - 1] - sum[i - 1][j - 1][k] - sum[i - 1][j][k - 1] - sum[i][j - 1][k - 1] ;
  }
}
}

几何

直线相交求交点

const int maxh=62;
#define rint register int
int cmp(double x){
   if(fabs(x)<eps) return 0;
   if(x>0) return 1;
   return -1;
}
double sqr(double x){
   return x*x;
}
struct point {
   double x,y;
   point(){}
   point(double a,double b):x(a),y(b){}
   void input(){
       cin>>x>>y;
   }
   friend point operator -(const point &a,const point &b){
       return point (a.x-b.x,a.y-b.y);
   }
   friend point operator *(const point &a,const double &b){
       return point (a.x*b,a.y*b);
   }
   friend point operator *(const double &b,const point &a){
       return point (a.x*b,a.y*b);
   }
   friend point operator /(const point &a,const double &b){
       return point (a.x/b,a.y/b);
   }
};
double cross(const point &a,const point &b){
   return a.x*b.y-a.y*b.x;
}
struct line {
   point a,b;
   line(){}
   line(point x,point y):a(x),b(y){}
   void input(){
       a.input();
       b.input();
   }
}a[N];
bool parallel(line a,line b){
   return !cmp(cross(a.a-a.b,b.a-b.b));
}
bool line_make_point(line a,line b,point &res){
   if(parallel(a,b)) return false;
   double s1=cross(a.a-b.a,b.b-b.a);
   double s2=cross(a.b-b.a,b.b-b.a);
   res=(s1*a.b-s2*a.a)/(s1-s2);
   return true;
}
double res=0;
int main() {
   cin>>n;
   for(int i=1;i<=n;i++){
       a[i].input();
   }
   for(int i=1;i<=n;i++)
       for(int j=1;j<=n;j++)
           for(int k=1;k<=n;k++){
               point x,y,z;
               if(!line_make_point(a[i],a[j],x)) continue;
               if(!line_make_point(a[i],a[k],y)) continue;
               if(!line_make_point(a[j],a[k],z)) continue;
               double b,c,d;
               b=sqrt(sqr(x.x-y.x)+sqr(x.y-y.y));
               c=sqrt(sqr(x.x-z.x)+sqr(x.y-z.y));
               d=sqrt(sqr(y.x-z.x)+sqr(y.y-z.y));
               double p=(b+c+d);
               res=max(res,p/*sqrt(p*(p-b)*(p-c)*(p-d))*/);
           }
   if(abs(res)<eps) {
       cout<<"no triangle";
   } else cout<<fixed<<setprecision(12)<<res;
   return 0;
}

圆与正方形的关系

struct node
{
 int x , y , r ;
}p[6] , z[6];
int check1(node a){
 if(a.x > z[0].x && a.x < z[1].x && a.y > z[0].y && a.y < z[3].y) return 1 ;
 for(int i = 0 ;i < 4 ;i ++){
    if(z[i].x == z[i + 1].x)
       if(a.x == z[i].x && a.y >= min(z[i].y , z[i + 1].y) && a.y <= max(z[i].y , z[i + 1].y)) return 2 ;
    if(z[i].y == z[i + 1].y)
       if(a.y == z[i].y && a.x >= min(z[i].x , z[i + 1].x) && a.x <= max(z[i].x , z[i + 1].x)) return 2 ;
  }
 return 0 ;
}
int check2(node a){
 int t = (p[0].x - a.x) * (p[0].x - a.x) + (p[0].y - a.y) * (p[0].y - a.y) ;
 if(t == p[0].r * p[0].r) return 2 ;
 if(t < p[0].r * p[0].r) return 1 ;
 return 0 ;
}
bool have(){
 for(int i = 0 ;i <= 4 ;i ++)
  if(check1(p[i]) == 1)  return 1 ;
 for(int i = 0 ;i < 4;i ++)
  if(check2(z[i]) == 1)  return 1 ;
 return 0 ;
}
bool touch(){
 for(int i = 0 ;i <= 4 ;i ++)
  if(check1(p[i]) == 2) return 1 ;
 for(int i = 0 ;i < 4 ;i ++)
  if(check2(z[i]) == 2) return 1 ;
 return 0 ;
}
int main(){
 int r ;
 cin >> p[0].x >> p[0].y >> p[0].r ;
 p[1].x = p[0].x + p[0].r , p[1].y = p[0].y ;
 p[2].x = p[0].x , p[2].y = p[0].y + p[0].r ;
 p[3].x = p[0].x - p[0].r , p[3].y = p[0].y ;
 p[4].x = p[0].x , p[4].y = p[0].y - p[0].r ;
 cin >> z[0].x >> z[0].y >> r;
 z[1].x = z[0].x + r , z[1].y = z[0].y ;
 z[2].x = z[0].x + r , z[2].y = z[0].y + r ;
 z[3].x = z[0].x , z[3].y = z[0].y + r ;
 z[4] = z[0] ;
 if(have()) puts("2") ;
 else if(touch()) puts("1") ;
 else puts("0") ;
 return 0 ;
}

圆与矩形相交面积

struct Point{    double x, y;
   Point() {}
   Point(double xx, double yy)
   {
       x = xx;
       y = yy;
   }
   Point operator-(Point s) { return Point(x - s.x, y - s.y); }
   Point operator+(Point s) { return Point(x + s.x, y + s.y); }
   double operator*(Point s) { return x * s.x + y * s.y; }
   double operator^(Point s) { return x * s.y - y * s.x; }
} p[M];
double max(double a, double b) { return a > b ? a : b; }
double min(double a, double b) { return a < b ? a : b; }
double len(Point a) { return sqrt(a * a); }  // ���� a �ij���
double dis(Point a, Point b) { return len(b - a); } // a �� b ֮���ľ���
double cross(Point a, Point b, Point c)             // (a , b) ��(a , c){
   return (b - a) ^ (c - a);
}
double dot(Point a, Point b, Point c) // (a , b) * (a , c){
   return (b - a) * (c - a);
}
int judge(Point a, Point b, Point c) // �ж� ��c �Ƿ��� �߶� ab ��{
   if (c.x >= min(a.x, b.x) && c.x <= max(a.x, b.x) && c.y >= min(a.y, b.y) && c.y <= max(a.y, b.y))
       return 1;
   return 0;
}
double area(Point b, Point c, double r) // Բ�� a �� �뾶 r �� �������� a , b , c �ཻ������{
   Point a(0.0, 0.0);
   if (dis(b, c) < eps)
       return 0.0;
   double h = fabs(cross(a, b, c)) / dis(b, c);
   if (dis(a, b) > r - eps && dis(a, c) > r - eps){
       double angle = acos(dot(a, b, c) / dis(a, b) / dis(a, c));
       if (h > r - eps)
           return 0.5 * r * r * angle;
       else if (dot(b, a, c) > 0 && dot(c, a, b) > 0){
           double angle1 = 2 * acos(h / r);
           return 0.5 * r * r * fabs(angle - angle1) + 0.5 * r * r * sin(angle1);
       }
       else return 0.5 * r * r * angle;
   }
   else if (dis(a, b) < r + eps && dis(a, c) < r + eps) return 0.5 * fabs(cross(a, b, c));
   else{
       if (dis(a, b) > dis(a, c))swap(b, c);
       if (fabs(dis(a, b)) < eps) return 0.0;
       if (dot(b, a, c) < eps) {
           double angle1 = acos(h / dis(a, b));
           double angle2 = acos(h / r) - angle1;
           double angle3 = acos(h / dis(a, c)) - acos(h / r);
           return 0.5 * dis(a, b) * r * sin(angle2) + 0.5 * r * r * angle3;
       }
       else{
           double angle1 = acos(h / dis(a, b));
           double angle2 = acos(h / r);
           double angle3 = acos(h / dis(a, c)) - angle2;
           return 0.5 * r * dis(a, b) * sin(angle1 + angle2) + 0.5 * r * r * angle3;
       }
   }
}
int main(){
   int n = 4;
   double rx, ry, R;
   scanf("%lf%lf%lf", &rx, &ry, &R);
   scanf("%lf%lf%lf%lf", &p[1].x, &p[1].y, &p[3].x, &p[3].y);
   p[2].x = p[1].x;
   p[2].y = p[3].y;
   p[4].x = p[3].x;
   p[4].y = p[1].y;
   p[5] = p[1];
   Point O(rx, ry);
   for (int i = 1; i <= n + 1; i++)
       p[i] = p[i] - O;
   O = Point(0, 0);
   double sum = 0;
   for (int i = 1; i <= n; i++){
       int j = i + 1;
       double s = area(p[i], p[j], R);
       if (cross(O, p[i], p[j]) > 0) sum += s;
       else sum -= s;
   }
   printf("%.4lf
", fabs(sum));
}

一个点是否在线段上

double direction( node p1,node p2,node p ){
   return ( p1.x -p.x )*( p2.y-p.y) -  ( p2.x -p.x )*( p1.y-p.y)   ;
}
int on_segment( node p1,node p2 ,node p ){
   double max=p1.x > p2.x ? p1.x : p2.x ;
   double min =p1.x < p2.x ? p1.x : p2.x ;
double max1=p1.y > p2.y ? p1.y : p2.y ;
   double min1=p1.y < p2.y ? p1.y : p2.y ;
   if( p.x >=min && p.x <=max &&
 p.y >=min1 && p.y <=max1 )
       return 1;
   else
       return 0;
}
bool check1(node p1 , node p2 , node q){
 if( !on_segment( p1,p2,q ) ) return 0 ;
 if( direction( q,p1,p2 )==0 )return 1 ;
 else return 0 ;
}
bool check(int x ,int y){
 for(int i = 1; i <= n ;i ++)
  if(x != i && y != i && check1(a[x] , a[y] , a[i])) return 0 ;
 for(int i = 1; i <= n ;i ++)
    if(check1(a[x] , a[y] , b[i]))
     return 0 ;
 return 1 ;
}

计算几何板子

// 直线相交求交点 , 凸包算法, 求点是否在多边形范围内
struct point {
   double x,y;
   point(){}
   point(double a,double b):x(a),y(b){}
   void input(){
       cin>>x>>y;
   }
   friend point operator -(const point &a,const point &b){
       return point (a.x-b.x,a.y-b.y);
   }
   friend point operator *(const point &a,const double &b){
       return point (a.x*b,a.y*b);
   }
   friend point operator *(const double &b,const point &a){
       return point (a.x*b,a.y*b);
   }
   friend point operator /(const point &a,const double &b){
       return point (a.x/b,a.y/b);
   }
}p[N] , s[N] ;
struct line {
   point a,b;
   line(){}
   line(point x,point y):a(x),b(y){}
   void input(){
       a.input();
       b.input();
   }
}a[N];
int cmp(double x){
   if(fabs(x)<eps) return 0;
   if(x>0) return 1;
   return -1;
}
double sqr(double x){
   return x*x;
}
double cross(const point &a,const point &b){
   return a.x*b.y-a.y*b.x;
}
bool parallel(line a,line b){
   return !cmp(cross(a.a-a.b,b.a-b.b));
}
bool line_make_point(line a,line b,point &res){
   if(parallel(a,b)) return false;
   double s1=cross(a.a-b.a,b.b-b.a);
   double s2=cross(a.b-b.a,b.b-b.a);
   res=(s1*a.b-s2*a.a)/(s1-s2);
   return true;
}
double dis(point a,point b)
{
   point c=a-b;
   return sqrt(c.x*c.x+c.y*c.y);
}
double cross(point &a,point &b)//叉乘{
   return a.x*b.y-a.y*b.x;
}
bool cmp(point a,point b)//极角排序{
   double x=cross(a-p[1],b-p[1]);//以p[1]为积点

   if(x>0) return 1;//让a处于b的顺时针
   if(x==0&&dis(a,p[1])<dis(b,p[1])) return 1;//角度相同按距离排序
   return 0;
}
//
double mulx(point p1,point p2,point p3){
   return cross(p2-p1,p3-p1);
}
double area(point *p,int n){
   if(n<3) return 0;
   p[n+1]=p[1];
   double sum=0;
   for(int i=1;i<=n;i++)
   {
       sum+=p[i].x*p[i+1].y-p[i].y*p[i+1].x;//不管这个多边形在哪,都以原点为分割点,就算原点在外面也可以算出,因为有正负可以抵消掉多余的
   }
   sum=fabs(sum/2.0);
   return sum;
}
// 判断点是否在这个多边形范围内
bool intubao(point *s,int n,point a){
   int f=0;
   for(int i=0;i<n;i++)
   {
       if(cross(s[(i+1)%n]-s[i],a-s[i])>0) f++;
   }
   //if(cross(s[1]-s[n],a-s[n])>0) f++;
   if(f==n) return 1;
   return 0;
}
// 先按照x , 然后y
bool cmp2(point a,point b){
   if (a.x!=b.x)
       return a.x<b.x;
   return a.y<b.y;
}
int n,q , m ;
void Tubao() {
 sort(p,p+n,cmp2);
 for(int i=0;i<n;i++){
     while(m>1&&mulx(s[m-2],s[m-1],p[i])<=0) m--;
     s[m++]=p[i];
 }
 int kk=m;
 for(int i=n-2;i>=0;i--){
     while(m>kk&&mulx(s[m-2],s[m-1],p[i])<=0) m--;
     s[m++]=p[i];
 }
 if(n>1)
     m--;
}

DP

求所有区间内任意个数相加和为k的总方案数

/*
题意:一个长度为n的数组,求任意[ L,R ]区间和为S的总数。
题解:01背包
dp[N]代表前i个数中和为N的数量
每次dp[0]+=1,我们01背包板子循环到第i个物品求的是前i个物品和为N的数量,并没有
[2,i]、[3,i]、[4,i]、…、[i,i]这些情况,少了i-1种情况答案肯定不对,所以我们只需要把dp[0]赋值为 1 + (i-1) 原始就为1,再加上少的i-1中情况。
*/
ll a[maxn],dp[maxn];
int main(){
  ll n,k;
  cin>>n>>k;
  for(int i=1;i<=n;i++) cin>>a[i];
  ll ans=0;
  for(int i=1;i<=n;i++){
  	dp[0]+=1;//[2,i]、[3,i]、[4,i]、...、[i,i]
  	for(int j=k;j>=a[i];j--)
  		dp[j]=(dp[j]+dp[j-a[i]])%mod;
  	ans=(ans+dp[k])%mod;//前i个数的和为K的数量
  }
  cout<<ans<<endl;
  return 0;
}

BM线性递推

#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const ll mod=1000000007;
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll n;
namespace linear_seq {
  const int N=10010;
  ll res[N],base[N],_c[N],_md[N];
  vector<int> Md;
  void mul(ll *a,ll *b,int k) {
      rep(i,0,k+k) _c[i]=0;
      rep(i,0,k) if (a[i]) rep(j,0,k) _c[i+j]=(_c[i+j]+a[i]*b[j])%mod;
      for (int i=k+k-1;i>=k;i--) if (_c[i])
          rep(j,0,SZ(Md)) _c[i-k+Md[j]]=(_c[i-k+Md[j]]-_c[i]*_md[Md[j]])%mod;
      rep(i,0,k) a[i]=_c[i];
  }
  int solve(ll n,VI a,VI b) { // a 系数 b 初值 b[n+1]=a[0]*b[n]+...
      ll ans=0,pnt=0;
      int k=SZ(a);
      assert(SZ(a)==SZ(b));
      rep(i,0,k) _md[k-1-i]=-a[i];_md[k]=1;
      Md.clear();
      rep(i,0,k) if (_md[i]!=0) Md.push_back(i);
      rep(i,0,k) res[i]=base[i]=0;
      res[0]=1;
      while ((1ll<<pnt)<=n) pnt++;
      for (int p=pnt;p>=0;p--) {
          mul(res,res,k);
          if ((n>>p)&1) {
              for (int i=k-1;i>=0;i--) res[i+1]=res[i];res[0]=0;
              rep(j,0,SZ(Md)) res[Md[j]]=(res[Md[j]]-res[k]*_md[Md[j]])%mod;
          }
      }
      rep(i,0,k) ans=(ans+res[i]*b[i])%mod;
      if (ans<0) ans+=mod;
      return ans;
  }
  VI BM(VI s) {
      VI C(1,1),B(1,1);
      int L=0,m=1,b=1;
      rep(n,0,SZ(s)) {
          ll d=0;
          rep(i,0,L+1) d=(d+(ll)C[i]*s[n-i])%mod;
          if (d==0) ++m;
          else if (2*L<=n) {
              VI T=C;
              ll c=mod-d*powmod(b,mod-2)%mod;
              while (SZ(C)<SZ(B)+m) C.pb(0);
              rep(i,0,SZ(B)) C[i+m]=(C[i+m]+c*B[i])%mod;
              L=n+1-L; B=T; b=d; m=1;
          } else {
              ll c=mod-d*powmod(b,mod-2)%mod;
              while (SZ(C)<SZ(B)+m) C.pb(0);
              rep(i,0,SZ(B)) C[i+m]=(C[i+m]+c*B[i])%mod;
              ++m;
          }
      }
      return C;
  }
  int gao(VI a,ll n) {
      VI c=BM(a);
      c.erase(c.begin());
      rep(i,0,SZ(c)) c[i]=(mod-c[i])%mod;
      return solve(n,c,VI(a.begin(),a.begin()+SZ(c)));
  }
};
int main() {
  /*push_back 进去前 8~10 项左右、最后调用 gao 得第 n 项*/
  vector<int>v;
  v.push_back(3);
  v.push_back(9);
  v.push_back(20);
  v.push_back(46);
  v.push_back(106);
  v.push_back(244);
  v.push_back(560);
  v.push_back(1286);
  v.push_back(2956);
  v.push_back(6794);
  int nCase;
  scanf("%d", &nCase);
  while(nCase--){
      scanf("%lld", &n);
      printf("%lld
",1LL * linear_seq::gao(v,n-1) % mod);
  }
}

搜索

A_star算法

第 K 短路
int h[N] , rh[N] , e[N] , ne[N] , w[N] , idx;
void add(int *h , int a , int b , int c){
   e[idx] = b , ne[idx] = h[a] , w[idx] = c , h[a] = idx ++ ;
}
int S , T , K ;
int dis[N] , f[N] , n , m , st[N] ;
void dij(){
   priority_queue<PII , vector<PII> , greater<PII> > q ;
   memset(dis , 0x3f , sizeof dis) ;
   dis[T] = 0 ;
   memset(st , 0 , sizeof st) ;
   q.push({0 , T}) ;
   while(q.size()){
        auto t = q.top() ; q.pop() ;
        int u = t.second ;
        if(st[u]) continue ;
        st[u] = 1 ;
        for(int i = rh[u] ; ~i ; i = ne[i]){
             int v = e[i] ;
             if(dis[v] > dis[u] + w[i])
              dis[v] = dis[u] + w[i] , q.push({dis[v] , v}) ;
         }
    }
    memcpy(f , dis , sizeof f) ;
    return ;
}
int a_star(){
   priority_queue<PIII , vector<PIII> , greater<PIII > > q ;
   q.push({f[S] , {0 , S}}) ;
   memset(st , 0 , sizeof st) ;
   while(q.size()){
        auto t = q.top() ; q.pop() ;
        int u = t.second.second , distance = t.second.first ;
        if(st[u] >= K) continue ;
        st[u] ++ ;
        if(u == T && st[u] == K) return distance ;
        for(int i = h[u] ; ~i ; i = ne[i]){
             int v = e[i] ;
             if(st[v] < K)
              q.push({distance + w[i] + f[v] , {distance + w[i] , v}}) ;
         }
    }
    return -1 ;
}
int main(){
 n = in() , m = in() ;
 memset(h , -1 , sizeof h ) , memset(rh , -1 , sizeof rh) ;
 for(int i = 1 , a , b , c ; i <= m ;i ++)
      a = in() , b = in() , c = in() , add(h , a , b , c) , add(h , b , a , c) , add(rh , b , a , c) , add(rh , a , b , c) ;
 S = 0 , T = n - 1 , K = 2 ;
 if(S == T) K ++ ;
 dij() ;
 memset(st , 0 , sizeof st) ;
 int t = a_star() ;
 cout << t << endl ;
 return 0 ;
}
/*
*/
原文地址:https://www.cnblogs.com/spnooyseed/p/13863378.html