biblioteca

Download as pdf or txt
Download as pdf or txt
You are on page 1of 14

Template Problema de Josephus O(n)

#include<bits/stdc++.h> //n: número de pessoas


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:

0, 1, 1, 2, 0, 2, 2, 1, 0, 1, 1, 2, 0, 2, 2, 1, 0, 1, 1, 2, 0, 2, 2, 1, 0,

You might also like