NOIP模拟5
声明:本文为博客园 1Liu 原创文章. 如果您看到此声明一般是该内容由其它网站通过脚本获取以骗取流量,为保证体验请至原文查看. 原文地址:https://www.cnblogs.com/1Liu/p/16919591.html
下发文件(密码为原 accoders 比赛密码)
战争(CF1578K)
一看到这个 k ≤ 20,一定是去在 k 上做文章.
对于只有加边的操作,就可以在 O(2k) 的时间内枚举能加的边,在其中判断是否合法.
对于只有删边的操作,也能够在 O(2k) 时间内枚举哪个点一定不选,也是判断是否合法.
正解的话,就是把这两种结合起来. 具体怎么结合:
对于被删的点,记录一下它的颜色. 如果这个颜色集合空了(全删掉了),就不再将这个颜色算在答案之内.
对于加入的点,对每个点和边的颜色记录一个 cnt,来维护每个点有没有被覆盖和一个集合内有多少条加边.
口胡的,如有错误请见谅.
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define pll pair<ll,ll>
#define maxn 100001
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
rg bool f=0;rll x=0;rg char ch=getchar();while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10);putchar(x%10|'0'); }
ll p,n,k,c[maxn],mx,cnt,nul,sum,ans,S,T;
ll sel[maxn],scnt[maxn],tot[maxn],cnta[maxn],cntb[maxn];
ll sela[maxn],tota[maxn],totb[maxn];
vector<ll> b[maxn];
unordered_set<ll> t[maxn],ban;
vector<pll> h;
bool fl[maxn],vis[maxn],fl2[maxn];
inline bool cmp(rg pll x,rg pll y) { return (c[x.first]^c[x.second])>(c[y.first]^c[y.second]); }
inline void dfs(rll x)
{
if(x==k) { if(sum+p-cnt-nul>ans) ans=sum+p-cnt-nul,S=T; return; } rll s=h[x].first,t=h[x].second;
if(c[s]^c[t])// sel 是否选过 scnt 每种颜色的删数
{
if(!sel[s]) { scnt[c[s]]++; if(scnt[c[s]]==b[c[s]].size()) nul++; }
sel[s]++;dfs(x+1);sel[s]--; if(!sel[s]) { if(scnt[c[s]]==b[c[s]].size()) nul--; scnt[c[s]]--; }
if(!sel[t]) { scnt[c[t]]++; if(scnt[c[t]]==b[c[t]].size()) nul++; } sel[t]++;T|=1<<x;dfs(x+1);
sel[t]--;T^=1<<x; if(!sel[t]) { if(scnt[c[t]]==b[c[t]].size()) nul--; scnt[c[t]]--; }
}
else// sela 是否选过 tota 加点 totb 加边
{
dfs(x+1); if(sel[s]||sel[t]) return; if(tota[c[s]]&&(tota[c[s]]*(tota[c[s]]-1)>>1)==totb[c[s]]) sum-=tota[c[s]],cnt--;
if(!sela[s]) tota[c[s]]++; if(!sela[t]) tota[c[s]]++; totb[c[s]]++;
if(tota[c[s]]&&(tota[c[s]]*(tota[c[s]]-1)>>1)==totb[c[s]]) sum+=tota[c[s]],cnt++;
sela[s]++;sela[t]++; T|=1<<x; dfs(x+1); sela[s]--;sela[t]--; T^=1<<x;
if(tota[c[s]]&&(tota[c[s]]*(tota[c[s]]-1)>>1)==totb[c[s]]) sum-=tota[c[s]],cnt--;
if(!sela[s]) tota[c[s]]--; if(!sela[t]) tota[c[s]]--; totb[c[s]]--;
if(tota[c[s]]&&(tota[c[s]]*(tota[c[s]]-1)>>1)==totb[c[s]]) sum+=tota[c[s]],cnt++;
}
}
int main()
{
freopen("war.in","r",stdin); freopen("war.out","w",stdout);
p=read();n=read(); for(rll i=1;i<=n;i++) b[c[i]=read()].emplace_back(i); k=read();
for(rll i=1;i<=k;i++) h.emplace_back(read(),read()); sort(h.begin(),h.end(),cmp); dfs(0); write(ans);putn;//write(S<<1);putn;
for(rll i=0;i<k;i++)// tot 删 cnta 加点 cntb 加边a
{
rll s=h[i].first,t=h[i].second;
if(c[s]^c[t]) { if(!(S&1<<i)) { if(!fl[s]) fl[s]=1,tot[c[s]]++; } else if(!fl[t]) fl[t]=1,tot[c[t]]++; }
else if(S&1<<i) { if(!vis[s]) vis[s]=1,cnta[c[s]]++; if(!vis[t]) vis[t]=1,cnta[c[t]]++; cntb[c[s]]++; }
}
for(rll i=1;i<=n;i++) if(!fl[i])
{
// cout<<'*'<<i<<'*';
if(cnta[c[i]]&&(cnta[c[i]]*(cnta[c[i]]-1)>>1)==cntb[c[i]]) { if(vis[i]) write(i),put_; }
else if(!fl2[c[i]]) write(i),put_,fl2[c[i]]=1;
}
return 0;
}
其实麻烦了,直接对要修改的那最多 40 个点记录是否选中即可.
肥胖 (CF1578L)
首先建一棵 Kruskal 重构树. (我竟然被这为什么还卡了半天,因为可以来回走而不去吃糖)
对于这棵重构树,对它进行一次 dp 操作. 记录一个 sum 表示到该点的总共吃糖重量. 然后对于每个点连接的 x 和 y,对 dp 取一个从 x 到 y 和从 y 到 x 的距离,对于上一步的 dp 与这一次的边权取个 min 即可. 别忘了减去另一个点的 sum.
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define maxn 200001
#define pll pair<ll,ll>
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
rg bool f=0;rll x=0;rg char ch=getchar();while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10);putchar(x%10|'0'); }
struct node
{
ll x,to,v;
inline friend bool operator<(rg node a,rg node b) { return a.v>b.v; }
}a[maxn];
ll n,m,ls,c[maxn],f[maxn],sum[maxn],dp[maxn];
inline ll find(rll x) { if(x^f[x]) f[x]=find(f[x]); return f[x]; }
int main()
{
freopen("fat.in","r",stdin); freopen("fat.out","w",stdout);
for(rll i=1;i<maxn;i++) f[i]=i; n=read();m=read();for(rll i=1;i<=n;i++) c[i]=read();
for(rll i=1;i<=m;i++) a[i]=(node){ read(),read(),read() }; sort(a+1,a+m+1);
memset(dp,0b00111111,sizeof(dp)); for(rll i=1;i<=n;i++) sum[i]=c[i];
for(rll i=1,x,y;i<=m;i++) if((x=find(a[i].x))^(y=find(a[i].to)))
{
f[x]=f[y]=ls=n+i; dp[n+i]=max(min(a[i].v,dp[y])-sum[x],min(a[i].v,dp[x])-sum[y]);
sum[n+i]=sum[x]+sum[y];
}
if(dp[ls]<=0) puts("-1"); else write(dp[ls]);
return 0;
}
分摊(CF1578J)
没时间,先鸽了. 送个参考链接
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define maxn 300001
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
rg bool f=0;rll x=0;rg char ch=getchar();while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10);putchar(x%10|'0'); }
ll n,v[maxn],fa[maxn][21],tot[maxn][21],dp[maxn][21];
vector<ll> g[maxn],sum[maxn],s[maxn];
inline void dfs1(rll x) { for(rll i=0;i<g[x].size();i++) dfs1(g[x][i]),v[x]+=v[g[x][i]]; }
inline void dfs2(rll x)
{
for(rll i=1;i<=20;i++) fa[x][i]=fa[fa[x][i-1]][i-1]; if(x)
{
if(sum[fa[x][0]].size()^1) dp[x][0]=sum[fa[x][0]][(ll)sum[fa[x][0]].size()-1-(sum[fa[x][0]].back()==v[x])];
else dp[x][0]=0; tot[x][0]=s[fa[x][0]].back()-v[x]; for(rll i=1;i<=20;i++)
tot[x][i]=tot[x][i-1]+tot[fa[x][i-1]][i-1],dp[x][i]=max(dp[x][i-1],dp[fa[x][i-1]][i-1]-tot[x][i-1]);
}
for(rll i=0;i<g[x].size();i++) dfs2(g[x][i]);
}
int main()
{
freopen("share.in","r",stdin); freopen("share.out","w",stdout);
n=read(); for(rll i=1;i<=n;i++) g[fa[i][0]=read()].emplace_back(i),v[i]=read(); dfs1(0);
for(rll i=1;i<=n;i++) sum[fa[i][0]].emplace_back(v[i]),s[fa[i][0]].emplace_back(0);
for(rll i=0;i<=n;i++)
{
sort(sum[i].begin(),sum[i].end());
for(rll j=0;j<sum[i].size();j++) s[i][j]=s[i][j-1+!j]+sum[i][j];
}
/*abort();*/ dfs2(0); for(rll i=1,x,sv;i<=n;i++)
{
x=i,sv=v[i]; while(x)
{
for(rll j=20;~j;j--) if(x&&sv>=dp[x][j]) sv+=tot[x][j],x=fa[x][j]; if(x)
{
rll pos=upper_bound(sum[fa[x][0]].begin(),sum[fa[x][0]].end(),sv)-sum[fa[x][0]].begin()-1,t=sv;
if(pos<0) sv+=t*(ll)s[fa[x][0]].size()-min(v[x],t);
else sv+=t*(s[fa[x][0]].size()-pos-1)+s[fa[x][0]][pos]-min(v[x],t); x=fa[x][0];
}
}
write(sv),putn;
}
return 0;
}
修路(CF1578B)
--END--
我的博客: 𝟷𝙻𝚒𝚞
本文链接: https://www.cnblogs.com/1Liu/p/16919591.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!