@Plutorabbit
2017-02-19T01:56:46.000000Z
字数 7168
阅读 2281
POI 2016 OI BZOJ
BZOJ-4345 ~ BZOJ-4348
先用优先队列构造出第k小的权值,然后DFS求出方案。
用线段树找比t小的最前面的元素
#include <bits/stdc++.h>using namespace std;typedef long long LL;int read(){int x=0; 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*10+ch-'0'; if (f) x=-x;return x;}const int NN = 1000005;int n,m,cnt,top,a[NN],num[NN],mn[NN<<2],st[NN];LL ans[NN];struct Q{LL x; int y;}tmp;bool operator < (Q xx,Q yy) { return xx.x > yy.x; }priority_queue<Q> que;void Build(int k,int l,int r){if (l == r) { mn[k] = a[l]; return; }int mid = (l+r) >> 1;Build(k<<1,l,mid), Build(k<<1|1,mid+1,r);mn[k] = min(mn[k<<1],mn[k<<1|1]);}int Query(int k,int l,int r,int x,LL y){if (x <= l){if (mn[k] > y) return 0;if (l == r) return l;}int mid = (l+r) >> 1,tmpp;if (x <= mid) if ((tmpp=Query(k<<1,l,mid,x,y))) return tmpp;return Query(k<<1|1,mid+1,r,x,y);}void DFS(int xx,LL res){if (!cnt) return;if (!res){--cnt;if (!cnt) for (int i=1;i<=top;++i) printf("%d ",st[i]);return;}for (int i=xx+1;i<=n;++i){i = Query(1,1,n,i,res);if (i) st[++top] = i, DFS(i,res-a[i]), --top; else break;}}int main(){n = read(), m = read()-1;if (m == 0) { puts("0"); return 0; }for (int i=1;i<=n;++i) a[i] = num[i] = read();sort(num+1,num+1+n);tmp.x = num[1], tmp.y = 1;que.push(tmp);for (int i=1;i<=m;++i){tmp = que.top(); que.pop();ans[i] = tmp.x;if (i < m && tmp.y < n){tmp.y ++, tmp.x += num[tmp.y], que.push(tmp);tmp.x -= num[tmp.y-1], que.push(tmp);}}for (int i=m;i&&ans[i]==ans[m];--i) ++cnt;printf("%lld\n",ans[m]);Build(1,1,n);DFS(0,ans[m]);return 0;}
树型动规看出来应该很简单吧QAQ
分两种情况。
1. 在这个点放wifi。那么可以用h[i][1],h[i][2]表示放1、2个wifi的最优解,用儿子的对应状态转移一下即可。
2. 不放wifi。此时i到儿子的路径有两种情况:被i的儿子覆盖;被i的儿子的儿子和i的父亲覆盖。令f[i][x][y]表示i不放的时候,父亲节点放x个,儿子节点放y个。转移起来比较复杂,把9种状态压缩一下做。
#include <bits/stdc++.h>using namespace std;int read(){int x=0; 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*10+ch-'0'; if (f) x=-x;return x;}const int INF = 0x3f3f3f3f,NN = 200005;int n,ans,tot=0,head[NN],f[NN][3][3],g[NN][3],h[NN][3],q[NN][3],t[3][3];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 DFS(int xx,int fa){h[xx][1] = 1, h[xx][2] = 2;memset(g[xx],0x3f,sizeof(g[xx])), memset(f[xx],0x3f,sizeof(f[xx]));f[xx][0][0] = 0;for (int i=head[xx];i;i=e[i].ne)if (e[i].v != fa){DFS(e[i].v,xx);int v = e[i].v, tmp = min(min(h[v][1],h[v][2]),q[v][1]);for (int i=0;i<3;++i) tmp = min(tmp,g[v][i]);h[xx][1] += tmp, h[xx][2] += min(tmp,q[v][2]);memset(t,0x3f,sizeof(t));for (int i=0;i<3;++i)for (int j=0;j<3;++j)if (f[xx][i][j] < INF){tmp = f[xx][i][j];for (int k=1;k<3;++k) t[min(2,i+k)][j] = min(t[min(2,i+k)][j],tmp+h[v][k]);for (int k=0;k<3;++k) t[i][max(2-k,j)] = min(t[i][max(2-k,j)],tmp+g[v][k]);}memcpy(f[xx],t,sizeof(t));}for (int i=0;i<3;++i)for (int j=0;j<=i;++j) g[xx][i] = min(g[xx][i],f[xx][i][j]);q[xx][1] = min(f[xx][0][1],f[xx][1][2]), q[xx][2] = f[xx][0][2];}int main(){n = read();int x,y;for (int i=1;i<n;++i) x = read(), y = read(), Build(x,y);DFS(1,0);ans = min(h[1][1],h[1][2]);for (int i=0;i<3;++i) ans = min(ans,g[1][i]);printf("%d\n",ans);return 0;}
nim游戏变种,其实就是要求有多少种d为个数约数,剩余异或和为0的方案。
因此我们可以排序,由于x异或之后一定转移到2x内的数,所以说复杂度
#include <bits/stdc++.h>using namespace std;int read(){int x=0; 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*10+ch-'0'; if (f) x=-x;return x;}const int mod = 1000000007, NN = (1<<20);int n,m,d,f[10][NN],c[NN],g[NN];int main(){n = read(), d = read();f[0][0] = 1;int x,l,t;for (int i=1;i<=n;++i) x = read(), ++c[x], m = max(m,x);for (int k=1;k<=m;++k)while (c[k]--){for (l=1;l<=k;l<<=1);for (int i=0;i<l;++i) g[i] = (f[d-1][i] + f[0][i^k]) % mod;for (int i=d-1;i;--i)for (int j=0;j<l;++j){if (j > (j^k)) continue;t = f[i][j];f[i][j] = (f[i-1][j] + f[i][j^k]) % mod;f[i][j^k] = (f[i-1][j^k] + t) % mod;}for (int i=0;i<l;++i) f[0][i] = g[i];}if (n % d == 0) f[0][0] = (f[0][0] - 1 + mod) % mod;printf("%d\n",f[0][0]);return 0;}
首先特判全部都是A或者全部都是B或者的情况。
然后把矩阵四周都填充上A,枚举一个块,分情况讨论:
1.暴力枚举四周两个块;
2.一个方向上在四周扩展两步;
3.一个角落上斜着扩展一步,再扩展另一步。
复杂度
感觉自己写得要死要活的了TAT
#include <bits/stdc++.h>using namespace std;int read(){int x=0; 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*10+ch-'0'; if (f) x=-x;return x;}const int NN = 1005;int n,m,tot,w,a[NN][NN],f[NN][NN],q[10005][3],ans;char ch[NN];struct S{int x,y,l,r,s;}s[NN*NN];void UP(int xx,int yy,int zz){ q[++tot][0]=xx; q[tot][1]=yy; q[tot][2]=zz; }int SZ(int xx) { return s[xx].s; }void M(int xx) { w = max(w,xx); }void Get(int xx,int yy,int zz){s[zz].s ++, f[xx][yy] = zz, s[zz].y = max(s[zz].y,xx), s[zz].r = max(s[zz].r,yy);if (a[xx+1][yy] && !f[xx+1][yy]) Get(xx+1,yy,zz);if (a[xx][yy+1] && !f[xx][yy+1]) Get(xx,yy+1,zz);}int main(){n = read();if (n == 1) { puts("1"); return 0; }for (int i=1,j;i<=n;++i)for (scanf("%s",ch+1),j=1;j<=n;++j) a[i][j] = (ch[j]=='B');int x,y,l,r,tmp;for (int i=1;i<=n;++i)for (int j=1;j<=n;++j)if (a[i][j] && !f[i][j]) s[++m].x = i, s[m].l = j, Get(i,j,m);if (m == 0) { puts("2"); return 0; }if (m == 1) { printf("%d\n",min(n*n,s[1].s+2)); return 0; }for (int i=1;i<=m;++i){w = tot = 0;x = s[i].x, y = s[i].y, l = s[i].l, r = s[i].r;for (int j=x;j<=y;++j){if (l > 2){if (a[j][l-2]) UP(f[j][l-2],0,0);else M(SZ(f[j][l-3])+(SZ(f[j-1][l-2])|SZ(f[j-1][l-1]))+(SZ(f[j+1][l-2])|SZ(f[j+1][l-1])));}if (r < n-1){if (a[j][r+2]) UP(f[j][r+2],0,0);else M(SZ(f[j][r+3])+(SZ(f[j-1][r+2])|SZ(f[j-1][r+1]))+(SZ(f[j+1][r+2])|SZ(f[j+1][r+1])));}}for (int j=l;j<=r;++j){if (x > 2){if (a[x-2][j]) UP(f[x-2][j],0,0);else M(SZ(f[x-3][j])+(SZ(f[x-2][j-1])|SZ(f[x-1][j-1]))+(SZ(f[x-2][j+1])|SZ(f[x-1][j+1])));}if (y < n-1){if (a[y+2][j]) UP(f[y+2][j],0,0);else M(SZ(f[y+3][j])+(SZ(f[y+2][j-1])|SZ(f[y+1][j-1]))+(SZ(f[y+2][j+1])|SZ(f[y+1][j+1])));}}if (a[x-1][l-1]){if (x>1) UP(f[x-1][l-1],f[x-2][l],0);if (l>1) UP(f[x-1][l-1],f[x][l-2],0);}if (a[y+1][l-1]){if (y<n) UP(f[y+1][l-1],f[y+2][l],0);if (l>1) UP(f[y+1][l-1],f[y][l-2],0);}if (a[x-1][r+1]){if (x>1) UP(f[x-1][r+1],f[x-2][r],0);if (r<n) UP(f[x-1][r+1],f[x][r+2],0);}if (a[y+1][r+1]){if (y<n) UP(f[y+1][r+1],f[y+2][r],0);if (r<n) UP(f[y+1][r+1],f[y][r+2],0);}if (l == r){if (x>1) UP(f[x-2][l],f[x-1][l-1],f[x-1][l+1]);if (y<n) UP(f[y+2][l],f[y+1][l-1],f[y+1][l+1]);}if (x == y){if (l>1) UP(f[x][l-2],f[x-1][l-1],f[x+1][l-1]);if (r<n) UP(f[x][r+2],f[x-1][r+1],f[x+1][r+1]);}for (int j=1;j<=tot;++j)for (int k=j+1;k<=tot;++k){tmp = SZ(q[j][0]) + SZ(q[j][1]) + SZ(q[j][2]);if (q[j][0] != q[k][0] && q[j][1] != q[k][0] && q[j][2] != q[k][0]) tmp += SZ(q[k][0]);if (q[j][0] != q[k][1] && q[j][1] != q[k][1] && q[j][2] != q[k][1]) tmp += SZ(q[k][1]);if (q[j][0] != q[k][2] && q[j][1] != q[k][2] && q[j][2] != q[k][2]) tmp += SZ(q[k][2]);M(tmp);}if (x>1 && l>1 && !a[x-1][l-1]){M(SZ(f[x-1][l-2])+(SZ(f[x-2][l])|SZ(f[x-2][l-1]))+(l==r?SZ(f[x-1][l+1]):0));M(SZ(f[x-2][l-1])+(SZ(f[x][l-2])|SZ(f[x-1][l-2]))+(x==y?SZ(f[x+1][l-1]):0));}if (x>1 && r<n && !a[x-1][r+1]){M(SZ(f[x-1][r+2])+(SZ(f[x-2][r])|SZ(f[x-2][r+1]))+(l==r?SZ(f[x-1][r-1]):0));M(SZ(f[x-2][r+1])+(SZ(f[x][r+2])|SZ(f[x-1][r+2]))+(x==y?SZ(f[x+1][r+1]):0));}if (y<n && l>1 && !a[y+1][l-1]){M(SZ(f[y+1][l-2])+(SZ(f[y+2][l])|SZ(f[y+2][l-1]))+(l==r?SZ(f[y+1][l+1]):0));M(SZ(f[y+2][l-1])+(SZ(f[y][l-2])|SZ(f[y+1][l-2]))+(x==y?SZ(f[y-1][l-1]):0));}if (y<n && r<n && !a[y+1][r+1]){M(SZ(f[y+1][r+2])+(SZ(f[y+2][r])|SZ(f[y+2][r+1]))+(l==r?SZ(f[y+1][r-1]):0));M(SZ(f[y+2][r+1])+(SZ(f[y][r+2])|SZ(f[y+1][r+2]))+(x==y?SZ(f[y-1][r+1]):0));}ans = max(ans,w+SZ(i)+2);}printf("%d\n",ans);return 0;}