@Plutorabbit
2017-02-19T19:30:42.000000Z
字数 4838
阅读 1685
BZOJ
OI
2016
BZOJ 4557 ~ BZOJ 4561
树形DP
: 的子树中,最高覆盖到向下第层
: 的子树全部覆盖,还能向上覆盖层
#include <bits/stdc++.h>
using namespace std;
const int NN = 500005, INF = 0x3f3f3f3f;
int n,m,D,tot=0;
int w[NN],head[NN],f[NN][25],g[NN][25];
bool mark[NN];
struct E
{
int ne,v;
}e[NN<<1];
void Build(int xx,int yy)
{
e[++tot].ne = head[xx], head[xx] = tot, e[tot].v = yy;
e[++tot].ne = head[yy], head[yy] = tot, e[tot].v = xx;
}
void DP(int xx,int fa)
{
if (mark[xx]) f[xx][0] = g[xx][0] = w[xx];
for (int i=1;i<=D;++i) g[xx][i] = w[xx];
g[xx][D+1] = INF;
for (int i=head[xx];i;i=e[i].ne)
if (e[i].v != fa)
{
DP(e[i].v,xx);
for (int j=D;j>=0;--j) g[xx][j] = min(g[xx][j] + f[e[i].v][j], g[e[i].v][j+1] + f[xx][j+1]);
for (int j=D;j>=0;--j) g[xx][j] = min(g[xx][j], g[xx][j+1]);
f[xx][0] = g[xx][0];
for (int j=1;j<=D+1;++j) f[xx][j] += f[e[i].v][j-1];
for (int j=1;j<=D+1;++j) f[xx][j] = min(f[xx][j-1], f[xx][j]);
}
}
int main()
{
scanf("%d%d",&n,&D);
int x,y;
for (int i=1;i<=n;++i) scanf("%d",&w[i]);
scanf("%d",&m);
for (int i=1;i<=m;++i) scanf("%d",&x), mark[x] = 1;
for (int i=1;i<n;++i) scanf("%d%d",&x,&y), Build(x,y);
DP(1,0);
printf("%d\n",f[1][0]);
return 0;
}
大力容斥
4个点,计算坏点分别有个,除掉重复的就可以了
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int NN = 2005;
const LL mod = 100000007;
int n,m,K;
LL cnt1=0,cnt2=0,cnt3=0,cnt4=0,ans;
struct POI
{
int x,y;
POI(int xx = 0, int yy = 0) : x(xx), y(yy) { }
bool operator < (const POI &xx) const { return x < xx.x || (x == xx.x && y < xx.y); }
bool operator == (const POI &xx) const { return x == xx.x && y == xx.y; }
}p[NN];
set <POI> mp;
inline bool In(int xx,int yy) { return xx>=0 && xx<=n && yy>=0 && yy<=m; }
inline void Cal(int xx,int yy,int zz)
{
if (!xx || !yy || zz<2) return;
zz = min(zz,xx+yy);
xx = min(xx,zz-1); yy = min(yy,zz-1);
cnt1 = (cnt1 + (LL)(zz-yy)*yy) % mod;
cnt1 = (cnt1 + ((LL)(zz-xx+yy-1)*(yy-zz+xx)>>1ll)%mod) % mod;
}
inline void Count(int xa,int ya,int xb,int yb)
{
if (In(xa,ya) && In(xb,yb))
{
int tmp = mp.count(POI(xa,ya)) + mp.count(POI(xb,yb));
++ cnt2;
cnt3 += tmp;
if (tmp > 1) ++ cnt4;
}
}
inline void Solve(int xa,int ya,int xb,int yb)
{
int dx = xb - xa, dy = yb - ya;
Count(xa+dy,ya-dx,xb+dy,yb-dx); Count(xa-dy,ya+dx,xb-dy,yb+dx);
if (abs(dx+dy) & 1) return;
dy = (dx+dy) >> 1, dx -= dy;
Count(xa+dx,ya+dy,xb-dx,yb-dy);
}
int main()
{
scanf("%d%d%d",&n,&m,&K);
for (int i=1;i<=min(n,m);++i) ans = (ans + (LL) i*(n-i+1) % mod *(m-i+1)) % mod;
for (int i=1;i<=K;++i)
{
scanf("%d%d",&p[i].x,&p[i].y); mp.insert(p[i]);
}
for (int i=1;i<=K;++i)
{
Cal(p[i].x,n-p[i].x,p[i].y); Cal(p[i].x,n-p[i].x,m-p[i].y);
Cal(p[i].y,m-p[i].y,p[i].x); Cal(p[i].y,m-p[i].y,n-p[i].x);
cnt1 = (cnt1 + min(p[i].x,p[i].y) + min(p[i].x,m-p[i].y) + min(n-p[i].x,p[i].y) + min(n-p[i].x,m-p[i].y)) %mod;
for (int j=1;j<i;++j) Solve(p[i].x,p[i].y,p[j].x,p[j].y);
}
ans = (ans - cnt1 + cnt2 - cnt3/3 + cnt4/6 + mod) % mod;
printf("%lld\n",ans);
return 0;
}
为什么连着两道数学相关啊QAQ
公式说不清楚怎么破啊QAQ
看代码?
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int NN = 105;
const LL mod = 1000000007;
int n,m,k;
LL ans,s[NN],rk[NN],fac[NN],inv[NN],f[NN],g[NN];
LL KSM(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;
}
inline LL C(int x,int y) { return fac[x] * inv[y] %mod * inv[x-y] %mod; }
int main()
{
scanf("%d%d%d",&n,&m,&k);
for (int i=1;i<=m;++i) scanf("%lld",&s[i]);
for (int i=1;i<=m;++i) scanf("%lld",&rk[i]);
fac[0] = inv[0] = 1;
for (int i=1;i<=100;++i) fac[i] = fac[i-1] * i % mod, inv[i] = KSM(fac[i],mod-2);
for (int i=n-1;i>=k;--i)
{
f[i] = C(n-1,i);
for (int j=1;j<=m;++j) f[i] = f[i] * C(n-1-i,rk[j]-1) % mod;
for (int j=i+1;j<n;++j) f[i] = (f[i] - f[j] * C(j,i) % mod + mod) % mod;
}
ans = 1;
for (int i=1;i<=m;++i)
{
g[0] = s[i];
for (int j=1;j<=n;++j)
{
g[j] = (KSM(s[i]+1,j+1)-1+mod) % mod;
for (int l=0;l<j;++l) g[j] = (g[j]-C(j+1,l)*g[l] %mod + mod) %mod;
g[j] = g[j] * KSM(j+1,mod-2) % mod;
}
LL tmp = 0, p = 1;
for (int j=0;j<=rk[i]-1;++j)
tmp = (tmp + C(rk[i]-1,j) * KSM(s[i], rk[i]-1-j) %mod *g[n-rk[i]+j] %mod *p +mod) % mod, p = -p;
ans = ans * tmp % mod;
}
printf("%lld\n",ans*f[k]%mod);
return 0;
}
感觉做法很迷QAQ
并没有做QAQ
两圆的关系只存在相离和包含
所以就可以像扫描线那样排序后从左到右扫QAQ
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int NN = 200005;
int n,tot;
LL ans,pos,f[NN];
struct Cir
{
LL x,y,r;
}c[NN];
struct POI
{
int num,x,op;
}b[NN<<1];
set <POI> se;
inline bool cmp(POI xx,POI yy) { return xx.x < yy.x; }
inline LL sqr(LL xx) { return xx*xx; }
inline bool operator < (POI xx,POI yy)
{
double dx = c[xx.num].y + xx.op * sqrt(sqr(c[xx.num].r)-sqr(pos-c[xx.num].x));
double dy = c[yy.num].y + yy.op * sqrt(sqr(c[yy.num].r)-sqr(pos-c[yy.num].x));
return (dx != dy) ? dx<dy : xx.op < yy.op;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;++i)
{
scanf("%lld%lld%lld",&c[i].x,&c[i].y,&c[i].r);
b[2*i-1] = (POI){i,(int)(c[i].x-c[i].r),1};
b[2*i] = (POI){i,(int)(c[i].x+c[i].r),-1};
}
sort(b+1,b+1+2*n,cmp);
set <POI> :: iterator it;
for (int i=1;i<=(n<<1);++i)
{
pos = b[i].x;
if (b[i].op == 1)
{
it = se.upper_bound((POI){b[i].num,0,-1});
if (it == se.end()) f[b[i].num] = 1;
else
{
if ((*it).op == 1) f[b[i].num] = -f[(*it).num];
else f[b[i].num] = f[(*it).num];
}
se.insert((POI){b[i].num,0,-1});
se.insert((POI){b[i].num,0,1});
}
else
{
se.erase((POI){b[i].num,0,-1});
se.erase((POI){b[i].num,0,1});
}
}
ans = 0ll;
for (int i=1;i<=n;++i) ans += sqr(c[i].r) * f[i];
printf("%lld\n",ans);
return 0;
}