@Plutorabbit
2017-02-19T11:30:42.000000Z
字数 4838
阅读 1860
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;}