暑假集训Day19 比赛题解
2023-08-05 16:22:13
总结
这次打下来,由于 T2 贪心不够完全,T3 模拟
感觉这次前三题也不难,都是可做的,T4 的 30pts 暴力也很白给,但是我想加调了两个小时 T2 的假树形 dp,然后就来不及打了。
赛后发现 T2 的贪心和我想的基本一致,但是枚举的东西略有不同,也就是我的不够贪心。T3 的构造不难想,有一个挺显然的性质但是我并没有去在意。T1 有可以不用数位 dp 的更好方法,但我也没去找了。
总而言之,下次可以不需要这么心急,可以先打个暴力当对拍都不错,不过也挺好了,感觉自己的算法思维也越来越强了呢,还是有不错的提升的。
T4 的正解因为我还没有看懂,所以就不放了,等我自己想明白了再来搞。
那还是先进入正题吧~
A
题目描述
有
思路
令
因为我上课的时候证明
思考正解,设我们选了取个数为
所以最终只需要求
对于
此时的瓶颈有两个了,第一个是
首先解决异或的问题,我们通过打表可以得到一个结论,当
证明也很简单:
我们设
显然
设
然后再通过分类讨论可以得到只有当
所以机智的我懒得思考有的没的,直接现场
ll n,m,sum,k,a[100005],f[2][2][102],A[102]; ll dfs(ll len,ll lim,ll isk){ if(~f[lim][isk][len])return f[lim][isk][len]; if(!len)return f[lim][isk][len]=isk; ll maxx=lim?A[len]:1,res=0; for(ll i=0;i<=maxx;i++){ if(len==k+1)res+=dfs(len-1,lim&(i==maxx),i==1); else res+=dfs(len-1,lim&(i==maxx),isk); } return f[lim][isk][len]=res; } ll solve(ll x){ memset(f,-1,sizeof(f)); ll cnt=0; while(x){ A[++cnt]=x&1; x>>=1; } return dfs(cnt,1,0); } int main(){ n=read(),m=read(); for(ll i=1;i<=m;i++){ a[i]=read(); sum^=a[i]; } if(n%4==0)sum^=n; else if(n%4==1)sum^=(n-1)^n; else if(n%4==2)sum^=(n-2)^(n-1)^n; if(!sum)puts("0"); else{ ll ans=0; k=__lg(sum); for(ll i=1;i<=m;i++){ if(a[i]&(1ll<<k))ans++; } ans+=solve(n); cout<<ans; } }
求
核心代码
ll ans=0; k=__lg(sum); for(ll i=1;i<=m;i++){ if(a[i]&(1ll<<k))ans++; } ans+=(n>>k+1ll)*(1ll<<k);//先把不含自己的方案数算上 ans+=max(n%(1ll<<k+1ll)-(1ll<<k)+1ll,0ll);//再加上如果 k 位有1的方案数 cout<<ans;
总得来说还是简单的,但是因为好不容易找出正解了考场上打出来也是挺开心的(打的比较细心,基本上就微调过大样例),后来发现原来不需要这样麻烦,甚至有些神仙通过打表找规律找到正解,悲伤。(郑神!!!%%%%)
B
问题描述
给你一棵树,每个节点得染成红色或者蓝色,
思路
一眼树形 dp,但是不知道具体怎么做,开始是想把每个儿子节点看成物品然后跑背包的,奈何本人技术力不够打不来这种背包,然后就没想着去拿这
还是看限制条件吧,“对于任意一个点,子树内
并且,我们观察到如果一个子树的大小是偶数,那只可能出现蓝色等于红色的情况,这种情况因为蓝色等于红色,怎么加都不会不合法,所以保证代价最小即可,不用理会。
而当大小为奇数时,有两种情况。
所以我们设计状态
其中
那
其中
怎么贪心取最优?我们假设先全选蓝色,然后把红色减蓝色的贡献加入优先队列,取最小的即可。
int n; // 0:R=B 1:R>B 2:R<B ll a[1000006],b[1000006],f[3][1000006],siz[1000006]; vector<int>F[1000006]; void dfs(int x,int fa){ priority_queue<ll,vector<ll>,greater<ll> >Q; siz[x]=1; ll ans=0; for(int y:F[x]){ if(y==fa)continue; dfs(y,x); siz[x]+=siz[y]; if(siz[y]&1){ ans+=f[2][y]; Q.push(f[1][y]-f[2][y]); }else ans+=f[0][y]; } if(!Q.size()){ f[1][x]=ans+a[x],f[2][x]=ans+b[x]; return; } if(siz[x]&1){ //奇数的时候,一定有偶数个子树不是偶siz //要么是少两个b然后选b,要么少两个a选a,要么不多不少选a或者选b //两种答案,各分两种情况讨论。 int cnt=Q.size()>>1;//枚举选几个a,不减1是持平的 cnt--; while(cnt--){ ans+=Q.top(),Q.pop(); } f[2][x]=min(ans+a[x],ans+Q.top()+b[x]); ans+=Q.top(); Q.pop(); f[1][x]=min(ans+a[x],ans+Q.top()+b[x]); }else{ //偶数的时候,一定有奇数个子树不是偶siz //要么是少a选b,要么是少b选a int cnt=Q.size()>>1;//枚举选几个a,这里是先少选a的 while(cnt--){ ans+=Q.top(),Q.pop(); } f[0][x]=min(ans+a[x],ans+Q.top()+b[x]); } } int main(){ n=read(); for(int i=1;i<=n;i++){ a[i]=read(),b[i]=read(); } for(int i=1;i<n;i++){ int u=read(),v=read(); F[u].push_back(v); F[v].push_back(u); } dfs(1,0); ll ans; if(n&1)ans=min(f[1][1],f[2][1]); else ans=f[0][1]; cout<<ans; }
一开始其实思路跟这个差不多,但是由于我不想开三维,就开了一维然后分奇偶讨论,天真地以为奇数大小的子树中除根的节点必然满足红色等于蓝色,然后方法差不多,直接把奇数情况的
下次讨论 dp 的时候不要想当然,要关注整体的贡献而不是个体的贡献(根节点的颜色不影响整体,看得是子树多的颜色),多思考,反思,看题也要仔细(一开始以为不算根)!!
C
分类讨论大挂了,不过问题不大,其实也想到了一些构造思想,但是没想到那么显然。
题意:
给定一个
思路
观察图中任意三个点的关系,发现要么是三元环,要么就是一个点指向另外两个点。三元环的个数不好算,但是第二个的个数好算,我们令
所以只需要最小化
提供两个构造方法:
- 奇数个点时显然每个点可以做到有
个出度,然后偶数个只需要在奇数个的基础上加一个点平摊出度即可
m=n; if(n+1&1)m--; for(int i=1;i<=m;i++){ for(int j=1;j<=m;j++){ if(i!=j&&((m-i+j)<=(m-1>>1)||(j-i<=(m-1>>1)&&j>i))) a[i][j]=1; } } if(n+1&1){ for(int i=1;i<=(m>>1);i++)a[i][n]=1; for(int i=(m>>1)+1;i<=m;i++)a[n][i]=1; } for(int i=1;i<=n;i++,puts("")){ for(int j=1;j<=n;j++){ printf("%d",a[i][j]); } }
- 就是隔一个连一个,这样基本可以平摊出度。
int n=read(); for(int i = 1;i<=n;i++) for(int j = i+1,t=1;j<=n;j++) a[i][j]=t,t=1-t; for(int i = 1;i<=n;i++) for(int j = i+1,t=0;j<=n;j++) a[j][i]=t,t=1-t; for(int i = 1;i<=n;i++){for(int j = 1;j<=n;j++)cout<<a[i][j];cout<<"\n";}
然后我目前听得懂的题目就这么多了,把 D 放出来让大佬们思考一下。
D
问题描述
给定一个
对于所有的
样例
in:
5 1 2 1 3 2 4 2 5
out
798595484 499122180 4 199648875 5
思路
我只想到了
本文作者:NBest
本文链接:https://www.cnblogs.com/NBest/p/17686910.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步