@Plutorabbit
2017-02-19T10:22:41.000000Z
字数 8878
阅读 2271
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 1000010
using 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]);
else
if (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 1000010
int 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;
}