@Plutorabbit
2017-02-19T02:22:41.000000Z
字数 8878
阅读 2448
SDOI 2016 BZOJ OI
BZOJ-4513 ~ BZOJ-4518
数位DP
f[i][0/1][0/1][0/1]表示考虑到第i位前i位[是/否]卡n的上界,卡m的上界,卡k的下界的数对个数
g[i][0/1][0/1][0/1]表示考虑到第i位前i位[是/否]卡n的上界,卡m的上界,卡k的下界的数对的和
#include <bits/stdc++.h>using namespace std;typedef long long LL;int T;LL n,m,k,mod,f[110][2][2][2],g[110][2][2][2],bin[65],ans;int main(){scanf("%d",&T);while (T--){scanf("%lld%lld%lld%lld",&n,&m,&k,&mod);--n, --m;ans = 0ll;bin[0]=1; for (int i=1;i<=63;++i) bin[i] = (bin[i-1]*2ll) % mod;memset(f,0,sizeof(f)), memset(g,0,sizeof(g));f[0][3][1][4] = 1, g[0][5][1][6] = 0;int p,q,t,A,B,C;for (int i=0;i<=63;++i)for (int a=0;a<2;++a)for (int b=0;b<2;++b)for (int c=0;c<2;++c)if (f[i][a][b][c]){p = ((n&(1ll<<(63-i)))==0)?0:1, q = ((m&(1ll<<(63-i)))==0)?0:1, t = ((k&(1ll<<(63-i)))==0)?0:1;for (int x=0;x<2;++x){if (a && x>p) continue;for (int y=0;y<2;++y){if (b && y>q) continue;int z = x^y;if (c && z<t) continue;A = (a && x==p)?1:0, B = (b && y==q)?1:0, C = (c && z==t)?1:0;f[i+1][A][B][C] = (f[i+1][A][B][C] + f[i][a][b][c]) % mod;g[i+1][A][B][C] = (g[i+1][A][B][C] + g[i][a][b][c] + ((z!=0)?bin[63-i]:0)*f[i][a][b][c] % mod) % mod;}}}k %= mod;for (int a=0;a<2;++a)for (int b=0;b<2;++b)for (int c=0;c<2;++c) ans = (ans + g[64][a][b][c] - k*f[64][a][b][c]%mod + mod) % mod;printf("%lld\n",ans);}return 0;}
质因数分解看有奇数/偶数个质因数
建图跑费用流
#include <iostream>#include <cstdio>#include <cmath>#include <algorithm>#include <cstring>#include <cstdlib>#include <queue>#define INF 100000000000000010#define LL long long#define NN 1000010using namespace std;int tot=1,n,m,a[NN],f[NN],prime[32000],head[NN],S,T,fa[NN];LL ans=0ll,cost=0ll,b[NN],c[NN],dis[NN];bool fprime[32100],vis[NN];queue<int> que;struct E{int ne,v,u;LL w,c;}e[NN];int read(){int xx; bool f=0; char CH;for (CH=getchar();CH<'0'||CH>'9';CH=getchar()) if (CH=='-') f=1;for (xx=0;CH>='0';CH=getchar()) xx=xx*10+CH-'0'; if (f) xx=-xx;return xx;}LL Read(){LL xx; bool f=0; char CH;for (CH=getchar();CH<'0'||CH>'9';CH=getchar()) if (CH=='-') f=1;for (xx=0;CH>='0';CH=getchar()) xx=xx*10+CH-'0'; if (f) xx=-xx;return xx;}void Build(int xx,int yy,LL zz,LL cc){e[++tot].ne=head[xx], head[xx]=tot, e[tot].v=yy, e[tot].u=xx, e[tot].w=zz, e[tot].c=cc;e[++tot].ne=head[yy], head[yy]=tot, e[tot].v=xx, e[tot].u=yy, e[tot].w=0, e[tot].c=-cc;}bool SPFA(){while (!que.empty()) que.pop();memset(dis,-128,sizeof(dis));memset(vis,0,sizeof(vis));dis[S]=0, que.push(S), vis[S]=1;while (!que.empty()){int now=que.front(); que.pop();vis[now]=0;for (int i=head[now];i;i=e[i].ne)if (e[i].w && dis[e[i].v]<dis[now]+e[i].c){dis[e[i].v]=dis[now]+e[i].c, fa[e[i].v]=i;if (!vis[e[i].v]) vis[e[i].v]=1, que.push(e[i].v);}}return dis[T]>=-INF;}LL MCF(){LL xx=INF;for (int i=fa[T];i;i=fa[e[i].u]) xx=min(xx,e[i].w);if (cost+xx*dis[T]<0) xx=-cost/dis[T];cost+=xx*dis[T];for (int i=fa[T];i;i=fa[e[i].u]) e[i].w-=xx, e[i^1].w+=xx;return xx;}int Fenjie(int xx){int total=0,x=xx;for (int i=1;i<=prime[0]&&prime[i]<=(int)sqrt(x);++i)while (xx%prime[i]==0) xx/=prime[i], ++total;if (xx!=1) ++total;return total;}bool Pri(int xx){for (int i=1;i<=prime[0]&&prime[i]<=(int)sqrt(xx);++i)if (xx%prime[i]==0) return 0;return 1;}int main(){n=read(), S=n+1, T=n+2;memset(fprime,0,sizeof(fprime));memset(prime,0,sizeof(prime));fprime[1]=1;for (int i=2;i<=32000;++i){if (!f[i]) prime[++prime[0]]=i;for (int j=1;prime[j]*i<=n&&j<=prime[0];++j){ fprime[prime[j]*i]=1; if (i%prime[j]==0) break;}}for (int i=1;i<=n;++i) a[i]=read();for (int i=1;i<=n;++i) b[i]=Read();for (int i=1;i<=n;++i) c[i]=Read();for (int i=1;i<=n;++i) f[i]=Fenjie(a[i])&1;for (int i=1;i<=n;++i)if (f[i]) Build(S,i,b[i],0); else Build(i,T,b[i],0);for (int i=1;i<=n;++i){for (int j=i+1;j<=n;++j)if (f[i]^f[j]){if (a[i]%a[j]==0 && Pri(a[i]/a[j]))if (f[i]&1) Build(i,j,INF,c[i]*c[j]);else Build(j,i,INF,c[i]*c[j]);elseif (a[j]%a[i]==0 && Pri(a[j]/a[i]))if (f[i]&1) Build(i,j,INF,c[i]*c[j]);else Build(j,i,INF,c[i]*c[j]);}}while (SPFA()){LL tmpp=MCF();if (tmpp==0ll) break;ans+=tmpp;}printf("%lld\n",ans);return 0;}
好久没有写树剖了QAQ
其实就是在树上维护好几条直线
注意判断交点什么的大小关系就可以了
#include <bits/stdc++.h>using namespace std;typedef long long LL;LL read(){LL x=0ll; bool f=0; char ch;for (ch=getchar();ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=1;for (;ch>='0'&&ch<='9';ch=getchar()) x=x*10ll+ch-'0'; if (f) x=-x;return x;}const int NN = 100005;const LL INF = 123456789123456789ll;int n,m,tot,id;int head[NN],sz[NN],fa[NN],pos[NN],num[NN],belong[NN],son[NN];LL ans,deep[NN];struct E{int ne,v;LL w;}e[NN<<1];struct TR{LL a,b,mn;}tr[NN<<2];inline void Build(int xx,int yy,LL zz){e[++tot].ne = head[xx], head[xx] = tot, e[tot].v = yy, e[tot].w = zz;e[++tot].ne = head[yy], head[yy] = tot, e[tot].v = xx, e[tot].w = zz;}void DFS1(int xx){sz[xx] = 1;for (int i=head[xx];i;i=e[i].ne)if (e[i].v != fa[xx]){fa[e[i].v] = xx, deep[e[i].v] = deep[xx] + e[i].w;DFS1(e[i].v);sz[xx] += sz[e[i].v];if (sz[e[i].v] > sz[son[xx]]) son[xx] = e[i].v;}}void DFS2(int xx,int chain){belong[xx] = chain, pos[xx] = ++id, num[id] = xx;if (son[xx]) DFS2(son[xx],chain);for (int i=head[xx];i;i=e[i].ne)if (e[i].v != fa[xx] && e[i].v != son[xx]) DFS2(e[i].v,e[i].v);}void Build_tr(int k,int l,int r){tr[k].a = 0, tr[k].b = tr[k].mn = INF;if (l == r) return;int mid = (l+r) >> 1;Build_tr(k<<1,l,mid), Build_tr(k<<1|1,mid+1,r);}LL Cal(LL a,LL b,LL x) { return a*deep[num[x]] + b; }void Update(int k,int l,int r,LL a,LL b){LL lx = Cal(tr[k].a,tr[k].b,l), rx = Cal(tr[k].a,tr[k].b,r), ly = Cal(a,b,l), ry = Cal(a,b,r);if (lx <= ly && rx <= ry) return;if (lx >= ly && rx >= ry) { tr[k].a = a, tr[k].b = b; return; }int mid = (l+r) >> 1;LL mx = Cal(tr[k].a,tr[k].b,mid), my = Cal(a,b,mid);if (mx >= my) { swap(a,tr[k].a), swap(b,tr[k].b), swap(lx,ly), swap(rx,ry), swap(mx,my); }if (lx >= ly) Update(k<<1,l,mid,a,b);else Update(k<<1|1,mid+1,r,a,b);}void Add(int k,int l,int r,int L,int R,LL a,LL b){tr[k].mn = min(tr[k].mn,min(Cal(a,b,L), Cal(a,b,R)));if (l == L && r == R) { Update(k,l,r,a,b); return; }int mid = (l+r) >> 1;if (R <= mid) Add(k<<1,l,mid,L,R,a,b);else if (L > mid) Add(k<<1|1,mid+1,r,L,R,a,b);else Add(k<<1,l,mid,L,mid,a,b), Add(k<<1|1,mid+1,r,mid+1,R,a,b);}void Query(int k,int l,int r,int L,int R){ans = min(ans,min(Cal(tr[k].a,tr[k].b,L), Cal(tr[k].a,tr[k].b,R)));if (l == L && r == R) { ans = min(ans, tr[k].mn); return; }int mid = (l+r) >> 1;if (R <= mid) Query(k<<1,l,mid,L,R);else if (L > mid) Query(k<<1|1,mid+1,r,L,R);else Query(k<<1,l,mid,L,mid), Query(k<<1|1,mid+1,r,mid+1,R);}inline void Solve_add(int x,int f,LL a,LL b){for (;belong[x] != belong[f]; x = fa[belong[x]]) Add(1,1,n,pos[belong[x]],pos[x],a,b);Add(1,1,n,pos[f],pos[x],a,b);}inline void Solve_query(int x,int f){for (;belong[x] != belong[f]; x = fa[belong[x]]) Query(1,1,n,pos[belong[x]],pos[x]);Query(1,1,n,pos[f],pos[x]);}inline int LCA(int xx,int yy){for (;belong[xx] != belong[yy]; deep[belong[xx]] > deep[belong[yy]] ? xx = fa[belong[xx]]: yy = fa[belong[yy]]);return deep[xx] < deep[yy] ? xx : yy;}int main(){n = read(), m = read();int x,y,z,lca,op;LL a,b;for (int i=1;i<n;++i) x = read(), y = read(), z = read(), Build(x,y,z);DFS1(1);DFS2(1,1);Build_tr(1,1,n);while (m--){op = read(), x = read(), y = read();if (op == 1){a = read(), b = read();lca = LCA(x,y);Solve_add(x,lca,-a,a*deep[x]+b);Solve_add(y,lca,a,a*(deep[x]-(deep[lca]*2))+b);}else{lca = LCA(x,y);ans = INF;Solve_query(x,lca), Solve_query(y,lca);printf("%lld\n",ans);}}return 0;}
Sam裸题QAQ
#include <bits/stdc++.h>using namespace std;typedef long long LL;const int MM = 200010;int n,x;LL ans;struct Sam{int tot,la,mx[MM],fa[MM],val[MM];map <int,int> a[MM];Sam() { la = ++tot; }void extend(int xx){int p = la, np = la = ++tot;mx[np] = mx[p] + 1, val[np] = 1;while (!a[p][xx] && p) a[p][xx] = np, p = fa[p];if (!p) fa[np] = 1;else{int q = a[p][xx];if (mx[p]+1 == mx[q]) fa[np] = q;else{int nq = ++tot;mx[nq] = mx[p]+1;a[nq] = a[q];fa[nq] = fa[q] , fa[np] = fa[q] = nq;while (a[p][xx] == q && p) a[p][xx] = nq, p = fa[p];}}ans += mx[np] - mx[fa[np]];printf("%lld\n",ans);}}SAM;int main(){scanf("%d",&n);for (int i=1;i<=n;++i) scanf("%d",&x), SAM.extend(x);return 0;}
小学递推错排
逆元搞搞
#include <iostream>#include <cstdio>#include <cmath>#include <cstring>#include <algorithm>#include <cstdlib>using namespace std;#define mod 1000000007ll#define LL long long#define NN 1002000#define N 1000010int n,m,T;LL fac[NN],f[NN];LL pow(LL xx,LL yy){LL sum=1ll;for (xx%=mod;yy;xx=xx*xx%mod,yy>>=1) if (yy&1) sum=sum*xx%mod;return sum;}void Pre(){fac[0] = 1ll;for (LL i=1;i<=N;++i) fac[i] = (fac[i-1] * i) % mod;f[0] = 1ll, f[1] = 0ll, f[2] = 1ll;for (LL i=3;i<=N;++i) f[i] = (f[i-1] + f[i-2]) % mod *(i-1ll) % mod;}int main(){Pre();scanf("%d",&T);while (T--){ scanf("%d%d",&n,&m);printf("%lld\n",(f[n-m]*fac[n]%mod*pow(fac[n-m],mod-2)%mod*pow(fac[m],mod-2)%mod)%mod);}return 0;}
斜率优化DP
DP方程:
表示到第个点,分成了段,表示1~j的前缀和
斜率优化搞一搞还是资磁的
#include <bits/stdc++.h>using namespace std;typedef long long LL;const int NN = 31005;int n,m,h,t,p,que[NN],summ;LL sum[NN],f[2][NN];LL sqr(LL xx) { return xx*xx; }double Y(int xx) { return (double)(f[p^1][xx]+sqr(sum[xx])); }double Cal(int xx,int yy) { return (Y(yy)-Y(xx))/(double)(sum[yy]-sum[xx]); }int main(){scanf("%d%d",&n,&m);for (int i=1;i<=n;++i){scanf("%lld",&sum[i]);summ += sum[i], sum[i] = (LL)sum[i]*m + sum[i-1];}p = 1;memset(f,0x3f,sizeof(f));f[0][0] = 0;for (int i=1;i<=n;++i) f[0][i] = sqr(sum[i]-summ);for (int k=1;k<=m;++k){h = t = 1, que[h] = 0;memset(f[p],0x3f,sizeof(f[p]));for (int i=1;i<=n;++i){while (h<t && Cal(que[h],que[h+1]) < (sum[i]-summ)*2) ++h;int j = que[h];f[p][i] = f[p^1][j] + sqr(sum[i]-sum[j]-summ);while (h<t && Cal(que[t-1],que[t]) > Cal(que[t],i)) --t;que[++t] = i;}p ^= 1;}printf("%lld\n",f[p^1][n]/m);return 0;}