using namespace std; //k: k-1 pessoas são poupadas e a k-ésima é executada #define sc(a) scanf("%d", &a) int jos(int n,int k){ #define sc2(a, b) scanf("%d%d", &a, &b) if(n==1) return 1; #define sc3(a, b, c) scanf("%d%d%d", &a, &b, &c) return (jos(n-1,k)+(k-1))%n+1; #define pri(x) printf("%d\n", x) } #define prie(x) printf("%d ",x) #define fi first Problema de Josephus O(log(n)), k=2 #define se second #define mp make_pair int jos2(int n) #define pb push_back { #define BUFF ios::sync_with_stdio(false) int a=1; #define db(x) cerr << #x << " == " << x << endl while(a<n) a=a*2; typedef long long int ll; return ((2*n)-a)%n+1; typedef long double ld; } typedef pair<int, int> ii; typedef vector<int> vi; Fenwick Tree (BIT) typedef vector<ii> vii; const int INF = 0x3f3f3f3f; ll FT[MAXN+1]; const ll LINF = 0x3f3f3f3f3f3f3f3fll; int N; const ld pi = acos(-1); void add(int a,ll v) int main() { { for(;a<=N;a+=a&(-a)) FT[a]+=v; return 0; } } ll get(int a) { ll sum=0; for(;a>0;a-=a&(-a)) sum+=FT[a]; return sum; } ll get_range(int a,int b) { return get(b)-get(a-1); } Fenwick Tree (Range Update) Inverso em Módulo (Euclides Extendido): //FT1 -> FENWICK TREE //Encontra o inverso de a módulo m //FT2 -> FENWICK TREE AUXILIAR int modInverse(int a, int m) // n -> número de elementos { // a,b - > range int m0 = m, t, q; // v -> valor a ser somado int x0 = 0, x1 = 1; void add(ll *FT,int p,ll v,int n) if (m == 1) { return 0; for(;p<=n;p+=(p&(-p))) while (a > 1) { { FT[p]+=v; // q is quotient } q = a / m; } t = m; ll get(ll *FT,int p) // m is remainder now, process same as { // Euclid's algo ll sum=0; m = a % m, a = t; for(;p>0;p-=(p&(-p))) t = x0; { x0 = x1 - q * x0; sum+=FT[p]; x1 = t; } } return sum; // Make x1 positive } if (x1 < 0) void add_range(ll *FT1,ll *FT2,int a,int b,ll v,int n) x1 += m0; { return x1; add(FT1,a,v,n); } add(FT1,b+1,-v,n); String Split (Útil): add(FT2,a, v*(a-1),n); add(FT2,b+1,-v*b,n); } vector<string> split(string str, char del) ll get_range(ll *FT1,ll *FT2,int a,int b,int n) { { vector<string> vec; a--; stringstream ss(str); return (get(FT1, b)*b -get(FT2, b)) - (get(FT1, string tok; a)*a - get(FT2, a)); while(getline(ss, tok, del)) vec.push_back(tok); } return vec; } Gambler’s Ruin Max Matching para grafo bipartido (Método Húngaro) //Em cada turno, o perdedor cede uma moeda ao oponente // Complexidade O(n^3) //Retorna a probabilidade de 1 ganhar o jogo vi G[MAXN]; double gamblersR(double p,int n1,int n2){ int match[MAXN]; double q=1-p; bool vis[MAXN]; if(p==0.5) return n1/double(n1+n2); int dfs(int v) //probabilidades iguais { return (1 - power((q/p),n1)) / (1 - if(vis[v]) return 0; //nao houve match power((q/p),n1+n2)); vis[v]=true; } for(int i=0;i<G[v].size();i++) Longest Increasing Subsequence (LIS) O(n log(n)) { int va=G[v][i]; if(match[va]==-1 || (dfs(match[va]))) //achou int aux[MAXN],endLis[MAXN]; { //usar upper_bound se puder >= match[va]=v; //armazena o match vi LisRec(vi v){ return 1; int n=v.size(); } int lis=0; } for (int i = 0; i < n; i++){ return 0; int it = lower_bound(aux, aux+lis, v[i]) - aux; } endLis[i] = it+1; int maxMatch(int n,int m) //tamanho dos conjuntos lis = max(lis, it+1); { aux[it] = v[i]; for(int i=0;i<m;i++) } match[i]=-1; vi resp; int ret=0; int prev=INF; for(int i=0;i<n;i++) for(int i=n-1;i>=0;i--){ { if(endLis[i]==lis && v[i]<=prev){ for(int j=0;j<n;j++) lis--; vis[j]=false; //zera os visitados prev=v[i]; ret+=dfs(i);//procura novo match a partir de i resp.pb(i); } } return ret; } } reverse(resp.begin(),resp.end()); return resp; } Persistent Fenwick Tree (com timestamp) KMP (String Matching) O(n+m) char T[MAX_N], P[MAX_N]; // T = text, P = pattern vector<pair<int,ll> > FT[MAXN]; int b[MAX_N], n, m; // b = back table, n = length of T, int v[MAXN]; m = length of P int n; void pre() void add(int i,int v,int time) { { int i = 0, j = -1; for(;i<=n;i+=i&(-i)) b[0] = -1; { while (i < m) ll last=FT[i].back().se; { FT[i].pb(mp(time,last+v)); while (j >= 0 && P[i] != P[j]) j = b[j]; } //diferentes, reseta j usando b } i++; j++; // se iguais, avança os 2 ponteiros ll get(int i,int time) b[i] = j; { } ll ret=0; } for(;i>0;i-=i&(-i)) void kmp() { { int pos= pre(); //monta a tabela de P upper_bound(FT[i].begin(),FT[i].end(),mp(time,INFLL))- int i = 0, j = 0; FT[i].begin()-1; while (i < n) //procura P em T ret+=FT[i][pos].se; { } while (j >= 0 && T[i] != P[j]) j = b[j]; return ret; //diferentes, reseta j usando b } i++; j++; // se iguais, avança os 2 ponteiros ll getRange(int a,int b,int time) if (j == m) { { return get(b,time)-get(a-1,time); printf("Found at %d\n", i - j); } j = b[j]; // prepara j para o próximo possível match } } } int u = q.front(); Max Flow (Dinic do Dilson) O(V^2E) q.pop(); for(vector<Edge>::iterator struct Edge e=g[u].begin();e!=g[u].end();e++) { { int v, rev; if(not e->cap or level[e->v] != -1) int cap; continue; Edge(int v_, int cap_, int rev_) : v(v_), level[e->v] = level[u] + 1; rev(rev_), cap(cap_) {} if(e->v == sink) return true; }; q.push(e->v); } struct MaxFlow } { return false; vector<vector<Edge> > g; } vector<int> level; queue<int> q; int blockingFlow(int u, int sink, int f) int flow, n; { if(u == sink or not f) return f; MaxFlow(int n_) : g(n_), level(n_), n(n_) {} int fu = f; for(vector<Edge>::iterator void addEdge(int u, int v, int cap) e=g[u].begin();e!=g[u].end();e++) { { if(u == v) return; if(not e->cap or level[e->v] != level[u] + Edge e(v, cap, int(g[v].size())); 1) continue; Edge r(u, 0, int(g[u].size())); int mincap = blockingFlow(e->v, sink, g[u].push_back(e); min(fu, e->cap)); g[v].push_back(r); if(mincap) } { g[e->v][e->rev].cap += mincap; bool buildLevelGraph(int src, int sink) e->cap -= mincap; { fu -= mincap; fill(ALL(level), -1); } while(not q.empty()) q.pop(); } level[src] = 0; if(f == fu) level[u] = -1; q.push(src); return f - fu; while(not q.empty()) } { int maxFlow(int src, int sink){ int mid=(l+r)/2; flow = 0; return while(buildLevelGraph(src, sink)) max(query(2*pos+1,l,mid,ql,qr),query(2*pos+2,mid+1,r,ql flow+= blockingFlow(src, sink, ,qr)); numeric_limits<int>::max()); } return flow; void update(int pos,int l,int r,int i,int k){ } if(l>i or r<i)return; }; if(l==r){ Heavy-Light Decompositon arr[i]=k; st[pos]=arr[i]; return; //HLD maior aresta no caminho, com update } int st[4*MAXN];//seg tree int mid=(l+r)/2; int arr[MAXN];//array para montar segtree update(2*pos+1,l,mid,i,k); ii edge[MAXN]; update(2*pos+2,mid+1,r,i,k); vii G[MAXN]; st[pos]=max(st[2*pos+1],st[2*pos+2]); int subt[MAXN];//tamanho da sub-arvore } int par[MAXN];//pai no dfs, usado para subir na HLD void dfs(int v,int p){ int chainHead[MAXN];//cabeca da chain na HLD subt[v]=1; int tot;//numero de chains par[v]=p; int currPos;//posicao no global array int mx=0; int posInArr[MAXN]; //posicao de v no array for(int i=0;i<G[v].size();i++){ int chainNum[MAXN]; //numero da chain de v int va=G[v][i].fi; int heavyChild[MAXN]; //filho pesado de v if(va!=p){ void build(int pos,int l,int r){ dfs(va,v); if(l==r){ subt[v]+=subt[va]; st[pos]=arr[l]; if(subt[va]>mx){ return; mx=subt[va]; } heavyChild[v]=va; int mid=(l+r)/2; } build(2*pos+1,l,mid); } build(2*pos+2,mid+1,r); } st[pos]=max(st[2*pos+1],st[2*pos+2]); } } int hld(int v,int costP,int p){ int query(int pos,int l,int r, int ql,int qr){ if(chainHead[tot]==-1) if(l>=ql && r<=qr)return st[pos]; chainHead[tot]=v; if(l>qr or r<ql)return 0; chainNum[v]=tot; posInArr[v]=currPos; build(0,0,n-1); arr[currPos++]=costP; char s[100]; for(int i=0;i<G[v].size();i++){ int q; int va=G[v][i].fi; sc(q); int cost=G[v][i].se; while(q--){ if(va==heavyChild[v]) int op; hld(va,cost,v); sc(op); } int a,b; for(int i=0;i<G[v].size();i++){ if(op==1){ int va=G[v][i].fi; int id,x; int cost=G[v][i].se; sc2(id,x); if(va!=p && va!=heavyChild[v]){ id--; tot++;//nova chain a=edge[id].fi; hld(va,cost,v); b=edge[id].se; } if(a==par[b])swap(a,b); } update(0,0,n-1,posInArr[a],x); } } int main(){ else{ int n; sc2(a,b); sc(n); a--,b--; for(int i=0;i<n;i++){ int ret=-INF; G[i].clear(); while(chainNum[a]!=chainNum[b]){ chainHead[i]=-1; if(chainNum[a]<chainNum[b]) heavyChild[i]=-1; swap(a,b); } ret=max(ret,query(0,0,n- tot=0; 1,posInArr[chainHead[chainNum[a]]],posInArr[a])); currPos=0; a=par[chainHead[chainNum[a]]]; for(int i=0;i<n-1;i++){ } int a,b,c; if(posInArr[a]>posInArr[b]) sc3(a,b,c); swap(a,b); a--,b--; ret=max(ret,query(0,0,n- G[a].pb(mp(b,c)); 1,posInArr[a]+1,posInArr[b])); G[b].pb(mp(a,c)); pri(ret); edge[i]=mp(a,b); } } } dfs(0,-1); return 0; hld(0,0,-1); } int resolve(string &s){ Aho Corasick int v = 0, r = 0; for (int i = 0; i < s.size(); i++) { const int N=100010; //tamanho da trie v = to[v][s[i]]; const int M=26; // tamanho do alfabeto if (fim[v]) r++, v = 0; int to[N][M], Link[N], fim[N]; } int idx = 1; return r; void add_str(string &s){ } int v = 0; for (int i = 0; i < s.size(); i++) { Hash Polinomial if (!to[v][s[i]]) to[v][s[i]] = idx++; v = to[v][s[i]]; #define MOD 1000000007 //Mod grande } #define base 33 //Primo um pouco maior que alfabeto fim[v] = 1; string ss; //String do hash } vector<ll> pot; //Potencias pre calculadas void process(){ vector<ll> pre; //Hash de prefixo queue<int> fila; void calcPot(int n){ fila.push(0); pot.pb(1); while (!fila.empty()) { for(int i=1;i<n;i++){ int cur = fila.front(); pot.pb(pot[i-1]*base); fila.pop(); pot[i]%=MOD; int l = Link[cur]; } fim[cur] |= fim[l]; } for (int i = 0; i < M; i++) { void calcPre(int n){ //LEMBRAR DE CHAMAR if (to[cur][i]) { pre.pb(ss[0]-'0'+1); if (cur != 0) for(int i=1;i<n;i++){ Link[to[cur][i]] = to[l][i]; pre.pb(pre[i-1]*base+ss[i]-'0'+1); else pre[i]%=MOD; Link[to[cur][i]] = 0; } fila.push(to[cur][i]); } } ll hash(int i,int j){ else { if(i==0)return pre[j]; to[cur][i] = to[l][i]; ll ret=pre[j]-pre[i-1]*pot[j-i+1]; } ret%=MOD; } if(ret<0)ret+=MOD; } return ret; } } int centroid=fcentroid(root,root); Centroid Decomposition O(n*logn) if(p==-1)p=centroid; ctree[centroid]=p; #define MAXN 100010 cvis[centroid]=true; vi G[MAXN]; //cout<<p+1<<"->"<<centroid+1<<endl; int ctree[MAXN]; for(int i=0;i<G[centroid].size();i++) int cvis[MAXN]; { int subt[MAXN]; int va=G[centroid][i]; int nn; if(!cvis[va]) void dfs(int v,int p) decompose(va,centroid); { } subt[v]=1; } nn++; int main() for(int i=0;i<G[v].size();i++) { { int n; int va=G[v][i]; sc(n); if(va!=p && !cvis[va]) for(int i=0;i<n-1;i++) { { dfs(va,v); int a,b; subt[v]+=subt[va]; sc2(a,b); } a--,b--; } G[a].pb(b); } G[b].pb(a); int fcentroid(int v,int p) } { decompose(0,-1); for(int i=0;i<G[v].size();i++) return 0; { } int va=G[v][i]; if(va!=p && subt[va]>nn/2 && !cvis[va])return fcentroid(va,v); } return v; } void decompose(int root,int p) { nn=0; dfs(root,root); Geometria 2D TYPE norm(pt a) { return a||a; } TYPE abs(pt a) { return sqrt(a||a); } typedef double TYPE; TYPE dist(pt a, pt b) { return abs(a - b); } const TYPE EPS = 1e-9; TYPE area(pt a, pt b, pt c) { return (a-c)%(b-c); } int ccw(pt a, pt b, pt c) {return sgn(area(a, b, c)); } inline int sgn(TYPE a) { return a > EPS ? 1 : (a >= - pt unit(pt a) { return a/abs(a); } EPS ? 0 : -1); } double arg(pt a) { return atan2(a.y, a.x); } inline int cmp(TYPE a, TYPE b) { return sgn(a - b); } pt f_polar(TYPE mod, double ang) { return pt(mod * cos(ang), mod * sin(ang)); } struct pt { inline int g_mod(int i, int n) { if(i == n) return 0; TYPE x, y; return i; } pt(TYPE x = 0, TYPE y = 0) : x(x), y(y) { } ostream& operator<<(ostream& o, pt p) { bool operator==(pt p) { return cmp(x, p.x) == 0 && return o << "(" << p.x << "," << p.y << ")"; cmp(y, p.y) == 0; } } bool operator<(pt p) const { /** funcoes de intercecao **/ return cmp(x, p.x) ? cmp(x, p.x) < 0 : cmp(y, //dentro do retangulo de vertices opostos r0 e r1 p.y) < 0; bool in_rect(pt r0, pt r1, pt p) } { bool operator<=(pt p) { return *this < p || *this return sgn(p.x - min(r0.x, r1.x)) >= 0 && == p; } sgn(max(r0.x, r1.x) - p.x) >= 0 && TYPE operator||(pt p) { return x*p.x + y*p.y; } sgn(p.y - min(r0.y, r1.y)) >= 0 && TYPE operator%(pt p) { return x*p.y - y*p.x; } sgn(max(r0.y, r1.y) - p.y) >= 0; pt operator~() { return pt(x, -y); } } pt operator+(pt p) { return pt(x + p.x, y + p.y); } //no segmento ab pt operator-(pt p) { return pt(x - p.x, y - p.y); } bool ps_isects(pt a, pt b, pt p) { return ccw(a,b,p) == pt operator*(pt p) { return pt(x*p.x - y*p.y, x*p.y 0 && in_rect(a,b,p); } + y*p.x); } //segmentos intersectam pt operator/(TYPE t) { return pt(x/t, y/t); } bool ss_isects(pt a0,pt a1,pt b0,pt b1) pt operator/(pt p) { return (*this * ~p)/(p||p); } { }; if(ccw(a0,a1,b0)*ccw(a0,a1,b1)==-1 and const pt I = pt(0,1); ccw(b0,b1,a0)*ccw(b0,b1,a1)==-1)return true; struct circle { return ps_isects(a0,a1,b0) or ps_isects(a0,a1,b1) pt c; TYPE r; or circle(pt c, TYPE r) : c(c), r(r) { } ps_isects(b0,b1,a0) or ps_isects(b0,b1,a1); }; } //intececao de retas parametrizadas p+vt, q+wt //distancia ponto segmento pt parametric_isect(pt p, pt v, pt q, pt w) double ps_dist(pt p, pt a, pt b) { { double t = ((q-p)%w)/(v%w); p = p - a; b = b - a; return p + v*t; double coef = min(max((b||p)/(b||b), TYPE(0)), } TYPE(1)); return abs(p - b*coef); //intersecao de segmentos } pt ss_isect(pt p, pt q, pt r, pt s) /** poligonos **/ { double p_signedarea(vector<pt> & pol) pt isect = parametric_isect(p, q-p, r, s-r); { if(ps_isects(p, q, isect) && ps_isects(r, s, double ret=0; isect)) return isect; for(int i=0;i<pol.size();i++) return pt(-INF, -INF); ret+=pol[i]%pol[(i+1)%pol.size()]; } return ret/2; } //intersecao de segmento com retangulo vector<pt> hull(vector<pt> pts) bool sr_isects(pt p0,pt p1,pt r0,pt r1) { { if(pts.size()<=1)return pts; if(in_rect(r0,r1,p0) or in_rect(r0,r1,p1))return vector<pt>ret; true; sort(pts.begin(),pts.end()); pt r2(r1.x,r0.y); int sz=0; pt r3(r0.x,r1.y); for(int i=0;i<pts.size();i++) return ss_isects(p0,p1,r0,r2) or { ss_isects(p0,p1,r2,r1) or while(sz>=2 && ccw(ret[sz-2],ret[sz- ss_isects(p0,p1,r1,r3) or ss_isects(p0,p1,r3,r0); 1],pts[i])<=0) } ret.pop_back(), sz--; //pontos colineares ret.pb(pts[i]); bool p_collinear(vector<pt> &v) sz++; { } if(v.size()<3) for(int i=pts.size()-2, t=sz+1;i>=0;i--) return true; { for(int i=2;i<v.size();i++) while(sz>=t && ccw(ret[sz-2],ret[sz- if(ccw(v[0],v[1],v[i])!=0) 1],pts[i])<=0) return false; ret.pop_back(), sz--; return true; ret.pb(pts[i]); } sz++; } if(px[i]<=pivot)lx.pb(px[i]); ret.pop_back(); else rx.pb(px[i]); return ret; for(int i=0;i<py.size();i++) } if(py[i]<=pivot)ly.pb(py[i]); vector<pt> cutPolygon(vector<pt>&pol,pt p0,pt p1) else ry.pb(py[i]); { pair<pt,pt> r1=closest_p(lx,ly); vector<pt> ret; pair<pt,pt> r2=closest_p(rx,ry); for(int i=0;i<pol.size();i++) double { delta=min(dist(r1.fi,r1.se),dist(r2.fi,r2.se)); pt q0=pol[i]; if(dist(r1.fi,r1.se)<dist(r2.fi,r2.se)) pt q1=pol[(i+1)%pol.size()]; ret=r1; if(ccw(p0,p1,q0)>=0) else ret.pb(q0); ret=r2; if(ss_isects(q0,q1,p0,p1)) vector<pt> cand; ret.pb(ss_isect(q0,q1,p0,p1)); for(int i=0;i<py.size();i++) } { return ret; if(cmp(abs(py[i].x-pivot.x),delta)<=0) } cand.pb(py[i]); //nao trata 2 pontos "iguais" } pair<pt,pt> closest_p(vector<pt> &px,vector<pt> &py) for(int i=0;i<cand.size();i++) { { pair<pt,pt> ret=mp(pt(-INF,-INF),pt(INF,INF)); for(int j=i+1;j<min((int)cand.size(),i+7);j++) if(px.size()<=3) { { double curr=dist(cand[i],cand[j]); double best=LINF; if(curr<delta) for(int i=0;i<px.size();i++) { for(int j=i+1;j<px.size();j++) delta=curr; if(dist(px[i],px[j])<best) ret=mp(cand[i],cand[j]); { } ret=mp(px[i],px[j]); } best=dist(px[i],px[j]); } } return ret; return ret; } } pt pivot=px[ (px.size()-1)/2]; vector<pt> lx,ly,rx,ry; for(int i=0;i<px.size();i++) Baby-step Giant-step Teorema de König (Cobertura de vértices e Max Match ) //Resolve Logaritmo Discreto a^x = b mod m, m primo em O(sqrt(n)*hash(n)) //Meet In The Middle, decompondo x = i * ceil(sqrt(n)) -j, i,j<=ceil(sqrt(n)) int babyStep(int a,int b,int m) { unordered_map<int,int> mapp; int sq=sqrt(m)+1; ll asq=1; for(int i=0; i<sq; i++) asq=(asq*a)%m; ll curr=asq; for(int i=1; i<=sq; i++) { if(!mapp.count(curr)) mapp[curr]=i; curr=(curr*asq)%m; } int ret=INF; curr=b; for(int j=0; j<=sq; j++) { Teorema de Erdős–Gallai (Existência de um Grafo): if(mapp.count(curr)) ret=min(ret,(int)(mapp[curr]*sq-j)); curr=(curr*a)%m; } if(ret<INF) return ret; return -1; } Lei dos cossenos Teorema de Pick (Polígonos simples em pontos inteiros): (Área, Pontos Internos e Borda)
Teorema de Herão
Burnside’s Lemma(Combinações a menos de rotações g):
Aproximação de Stirling
Fibonacci em log
Período de Pisano (Teoria dos Números):
Para Qualquer inteiro N, a sequência Fibonacci tomada módulo N é
periódica. O tamanho do período é chamado de π(n)(período de Pisano). Teorema de Euler (para poliedros convexos): Como exemplo, π(3)=8. Veja os primeiros fibonacci módulo 3: