====== 2020牛客暑期多校训练营(第十场) ====== ===== 比赛情况 ===== ^题号 ^A ^B ^C ^D ^E ^F ^G ^H ^I ^J | ^状态 |O |- |- |Ø |O |- |- |- |! |O | //O 在比赛中通过 Ø 赛后通过 ! 尝试了但是失败了 - 没有尝试// **比赛时间** 2020-08-10 12:00-17:00 ===== 题解 ===== ==== D - Hearthstone Battleground ==== 容易想到要贪心的用植物去破盾,所以优先用有亡语的随从生成植物去破盾,注意每次攻击前要清除对方的植物。 /* #pragma GCC optimize(2) #pragma GCC optimize(3,"Ofast","inline") */ #include #define ALL(x) (x).begin(),(x).end() #define ll long long #define db double #define ull unsigned long long #define pii_ pair #define mp_ make_pair #define pb push_back #define fi first #define se second #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define per(i,a,b) for(int i=(a);i>=(b);i--) #define show1(a) cout<<#a<<" = "< \\ ==== E - Game ==== 可以证明如果一个形状的右侧都是小于等于某一高度的时候可以保证左侧的高于某一高度的砖块可以被填进坑里,所以我们可以二分答案,然后贪心验证即可。 #include using namespace std; const int N = 1e5+5; typedef long long ll; int a[N],n; ll sum[N]; bool check(int hei) { ll rem = 0; for (int i = n;i>= 1;i--) { if (a[i]>hei)rem+=a[i]-hei; if (a[i] (ll)hei*(i-1)-sum[i-1])return false; } return true; } int main() { int cas; scanf("%d",&cas); while (cas--) { scanf("%d",&n); for (int i = 1;i<= n;i++) { scanf("%d",&a[i]); sum[i] = sum[i-1]+a[i]; } int l = 1,r = 1e9+5; while (l>1; if (check(mid))r = mid; else l = mid+1; } printf("%d\n",l); } return 0; } \\ ==== J - Identical Trees ==== 假设我们已经知道了两个树使任意两个子树标号相同的编辑代价,我们可以将两两之间同构的子树进行匹配,然后求一个最小完美匹配代价。于是我们可以记录每一个子树的树高,从树高小的开始算编辑代价,然后一层一层转移即可。其中判断树是否同构用树hash,其余部分就是一个用费用流转移的dp #include using namespace std; const int N = 505; int pri[N],pcnt; bool visp[100005]; int f[N][N],n; void initprime() { for (int i = 2;pcnt<500;i++) { if (!visp[i]) pri[++pcnt] = i; for (int j = 2;i*j < 1e5;j++) visp[i*j] = true; } } struct Edge { int nxt,to; }; struct Tree { int head[N],tot; Edge e[N<<1]; void init() { memset(head,0,sizeof(head)); tot = 0; } void add(int x,int y) { e[++tot].nxt = head[x];head[x] = tot;e[tot].to = y; e[++tot].nxt = head[y];head[y] = tot;e[tot].to = x; } unsigned int thash[N]; int size[N],thei[N],fa[N]; void dfs(int x,int f) { fa[x] = f; thash[x] = 1; thei[x] = 1; size[x] = 1; for (int i = head[x];i;i=e[i].nxt)if(e[i].to!=fa[x]) { dfs(e[i].to,x); thei[x] = max(thei[x],thei[e[i].to]+1); thash[x] += thash[e[i].to]*pri[size[e[i].to]]; size[x]+=size[e[i].to]; } } }t1,t2; bool cmp(const int &a,const int &b) { return t1.thei[a] < t1.thei[b]; } int id[N]; struct Max_Flow{ int head[N<<1],last[N<<1],pre[N<<1],vis[N<<1],dis[N<<1],flow[N<<1],s,t,tot; struct edge {int u,v,w,c,nxt;}es[502010]; void addedge(int u,int v,int w,int c) { es[++tot] = (edge){u,v,w,c,head[u]}; head[u] = tot; } void add(int u,int v,int w,int c) {addedge(u,v,w,c);addedge(v,u,0,-c);} void init(int mx) { for (int i = 0;i <= mx+1;i++)head[i] = -1; tot = -1; s = 0,t = mx+1; } bool spfa(int mx) { for (int i = 0;i<= mx+1;i++)dis[i] = flow[i] = 0x3f3f3f3f,vis[i] = 0; queue q;q.push(s); vis[s] = 1,dis[s] = 0,pre[t] = -1; while(!q.empty()){ int u = q.front();q.pop(); vis[u] = 0; for(int i=head[u];~i;i=es[i].nxt){ int v = es[i].v,w = es[i].w,c = es[i].c; if(w>0 && dis[v] > dis[u] + c){ dis[v] = dis[u] + c; pre[v] = u; last[v] = i; flow[v] = min(flow[u],w); if(!vis[v]){ vis[v] = 1; q.push(v); } } } } return ~pre[t]; } pair MCMF(int mx) { pair res = make_pair(0,0); while(spfa(mx)){ int now = t; res.first += flow[t]; res.second += flow[t] * dis[t]; while(now != s){ es[last[now]].w -= flow[t]; es[last[now]^1].w += flow[t]; now = pre[now]; } } return res; } }mcmf; void calc(int x,int y) { vectorsonx,sony; sonx.clear();sony.clear(); for (int i = t1.head[x];i;i=t1.e[i].nxt) if (t1.e[i].to!=t1.fa[x]) { sonx.push_back(t1.e[i].to); } for (int i = t2.head[y];i;i=t2.e[i].nxt) if (t2.e[i].to!=t2.fa[y]) { sony.push_back(t2.e[i].to); } mcmf.init(sonx.size()+sony.size()); for (int i = 0;i < sonx.size();i++) for (int j = 0;j < sony.size();j++) { int sx = sonx[i],sy = sony[j]; if (f[sx][sy]!=-1) { mcmf.add(i+1,j+1+sonx.size(),1,f[sx][sy]); } } for (int i = 0;i < sonx.size();i++) mcmf.add(0,i+1,1,0); for (int i = 0;i < sony.size();i++) mcmf.add(i+1+sonx.size(),sonx.size()+sony.size()+1,1,0); f[x][y] = (x!=y) + mcmf.MCMF(sonx.size()+sony.size()).second; } int main() { int x; scanf("%d",&n); t1.init(); t2.init(); initprime(); int root1=1,root2=1; for (int i = 1;i<= n;i++) { scanf("%d",&x); if (x!=0)t1.add(x,i); else root1 = i; } for (int i = 1;i<= n;i++) { scanf("%d",&x); if (x!=0)t2.add(x,i); else root2 = i; id[i] = i; } t1.dfs(root1,0); t2.dfs(root2,0); sort(id+1,id+n+1,cmp); for (int i = 1;i<= n;i++) for (int j = 1;j<= n;j++) { if (t1.thei[i]==1 && t2.thei[j]==1) f[i][j] = (i!=j); else f[i][j] = -1; } for (int i = 1;i<= n;i++) { int x = id[i]; if (t1.thei[x]!=1) for (int j = 1;j<= n;j++) { int y = j; if (t2.thei[y] == t1.thei[x] && t1.thash[x] == t2.thash[y]) calc(x,y); } } printf("%d\n",f[root1][root2]); return 0; } \\