牛客周赛 Round 39(A,B,C,D,E,F,G)

比赛链接

官方题解(视频)

B题是个贪心。CD用同余最短路,预处理的完全背包,多重背包都能做,比较典型。E是个诈骗,暴力就完事了。F是个线段树。G是个分类大讨论,出题人钦定的本年度最佳最粪 题目


A 小红不想做炸鸡块粉丝粉丝题

思路:

签到

code:

#include <iostream>
#include <cstdio>
using namespace std;int a,tot;int main(){cin>>a;tot=a;for(int i=2,t;i<=6;i++)cin>>t,tot+=t;if(a*30>=tot)puts("No");else puts("Yes");return 0;
}

B 小红不想做鸽巢原理

思路:

emmmm不太清楚和鸽巢原理有啥关系,就是个贪心的思路。

因为是 k k k k k k 个取走,所以假设一共有 t o t tot tot 个小球,最后会剩下 t o t % k tot\%k tot%k 个小球。因为要剩下的种类尽可能少,那么我们尽可能留下数量多的种类就行了。

code:

#include <iostream>
#include <cstdio>
#include <set>
using namespace std;
const int maxn=1e5+5;
typedef long long ll;int n,k;
ll tot=0;
set<int> S;int main(){cin>>n>>k;for(int i=1,t;i<=n;i++){cin>>t;S.insert(t);tot+=t;}tot%=k;if(tot==0){cout<<0<<endl;return 0;}int ans=0;for(auto it=S.rbegin();it!=S.rend();it++){ans++;if(tot>*it)tot-=*it;else break;}cout<<ans<<endl;return 0;
}

C,D 小红不想做完全背包

思路:

和寒假营第二场的D题是同种类型的题,做法有三:同余最短路,带预处理的完全背包,多重背包。

因为我们只想要是 p p p 的倍数,而这个数是什么我们不关心,所以我们用到的数都直接模 p p p 即可,当模 p p p 等于零的时候就是 p p p 的倍数了,这就算是比较典型板子 的带同余的完全背包问题了。

它和一般的完全背包还不太一样,普通的完全背包跑一趟就够了,因为重量不会无缘无故减少,我们只要从小到大跑一遍就能考虑到所有情况了,但是带同余的话重量就有可能减少了。比如容量为 7 7 7,物品的重量为 3 3 3,不带只跑一遍和带了跑到重复为止的结果是不一样的,如下图:

容量:0 1 2 3 4 5 6不带:0 0 1 0 0 2 0
带了:5 3 1 6 4 2 7

一般来说,我们从某个位置出发,为了跑到第一次重复,至少需要跑 p 2 g c d ( a i , p ) \dfrac {p^2}{gcd(a_i,p)} gcd(ai,p)p2 次(设 a i ∗ x ≡ a i ( m o d p ) a_i*x\equiv a_i\pmod p aixai(modp),解出来 x = p g c d ( a i , p ) + 1 x=\dfrac p{gcd(a_i,p)}+1 x=gcd(ai,p)p+1,也就是说一趟只用跑 p g c d ( a i , p ) \dfrac p{gcd(a_i,p)} gcd(ai,p)p 次就可以停了,再以每位置开始跑一趟,一共 p ∗ p g c d ( a i , p ) p*\dfrac p{gcd(a_i,p)} pgcd(ai,p)p 次)。再算上有 n n n 件物品,这样时间复杂度就爆了, 最坏情况 O ( n ∗ p 2 ) O(n*p^2) O(np2)

大致代码如下,TLE了(数据太弱了,居然就T了三个点,而且如果就算不枚举开始位置,只跑一次,甚至只WA三个点,经过某些神秘的顺序安排,居然还能AC,给人一种做法是正确的的错觉)

	cin>>n>>p;vector<int> a(n);for(int i=0,t;i<n;i++){cin>>t;a[i]=t%p;}sort(a.begin(),a.end());a.erase(unique(a.begin(),a.end()),a.end());n=a.size();vector<int> dp(p+5,1e9);for(auto x:a){dp[x]=1;for(int idx=0;idx<p;idx++)for(int i=1,t=(idx+x)%p;i<p/gcd(x,p);i++,t=(t+x)%p)dp[(t+x)%p]=min(dp[(t+x)%p],dp[t]+1);}cout<<dp[0];

发现我们没必要从每个位置开始都跑 p g c d ( a i , p ) \dfrac p{gcd(a_i,p)} gcd(ai,p)p 次,我们用多个物品得到的重量是固定的,我们不如一开始就处理好,然后直接拿来用。具体来说,设 c s t [ i ] cst[i] cst[i] 表示增加重量为 i i i 需要使用多少个物品,多个物品可以都处理到一个 c s t [ i ] cst[i] cst[i],预处理的时间复杂度为 n ∗ p g c d ( a i , p ) n*\dfrac p{gcd(a_i,p)} ngcd(ai,p)p,使用的时候直接把 c s t [ i ] cst[i] cst[i] 当作物品跑完全背包,每个物品只跑一趟即可。

为什么预处理后不需要跑多趟了?原来我们用物品 a i a_i ai 跑第一次的时候,这时相当于用 c s t [ a i % p ] cst[a_i\%p] cst[ai%p] 跑一次,原来我们用物品 a i a_i ai 跑第二次的时候,这时相当于用 c s t [ 2 ∗ a i % p ] cst[2*a_i\%p] cst[2ai%p] 跑一次,原来我们用物品 a i a_i ai 跑第三次的时候,这时相当于用 c s t [ 3 ∗ a i % p ] cst[3*a_i\%p] cst[3ai%p] 跑一次,类推,甚至我们多个物品同时处理后,这个 c s t cst cst 值还会更小,答案更优。因此我们原本每个位置每个物品跑多次,现在只要每个位置每个 c s t cst cst 跑一次就可以了。

因此完全背包部分时间复杂度就优化为了 O ( p 2 ) O(p^2) O(p2)。总的时间复杂度就优化为了 O ( n ∗ p g c d ( a i , p ) + p 2 ) O(\dfrac {n*p}{gcd(a_i,p)}+p^2) O(gcd(ai,p)np+p2),最坏 O ( n p + p 2 ) O(np+p^2) O(np+p2)

另外同余最短路和多重背包也是正确的做法,数据弱,奇奇怪怪的做法也能日过去。

code:

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=2005;int n,p;
int gcd(int a,int b){while(b)b^=a^=b^=a%=b;return a;
}int main(){cin>>n>>p;vector<int> a(n);for(int i=0,t;i<n;i++){cin>>t;a[i]=t%p;}sort(a.begin(),a.end());a.erase(unique(a.begin(),a.end()),a.end());n=a.size();vector<int> cst(p+5,1e9),dp(p+5,1e9);for(auto x:a){for(int i=1,cur=x;i<=p;i++,cur=(cur+x)%p){cst[cur]=min(cst[cur],i);}}for(int i=0;i<p;i++){int x=cst[i];//i步数 x代价 dp[i]=min(dp[i],x);for(int j=i;j<p+i;j++)dp[j%p]=min(dp[j%p],dp[(j-i+p)%p]+x);}cout<<dp[0];return 0;
}

E 小红不想做莫比乌斯反演杜教筛求因子和的前缀和

思路:

之前练习赛出了一个名字差不多的题,特难。这次出题人估计是想骗做题人给自己上压力,不过可惜放在了 E E E 题的位置上。没骗到。

枚举长 n n n 和宽 m m m,然后算出 p p p,统计答案个数即可。

code:

#include <iostream>
#include <cstdio>
using namespace std;int n,m,p,x;
int ans=0;int main(){cin>>n>>m>>p>>x;for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if((x-i*j)%(2*(i+j))==0 && (x-i*j)/(2*(i+j))>=1 && (x-i*j)/(2*(i+j))<=p)ans++;cout<<ans;return 0;
}

F 小红不想做模拟题

思路:

区间修改,区间查询,还是比较明显能想到线段树的。

当我们区间推平时,比如推平了 a a a 串的区间 [ l , r ] [l,r] [l,r],把它变成 1 1 1,那么这一段区间 1 1 1 的对数就变成了 b b b 串这段区间中 1 1 1 的个数,同理推平另一个串。所以我们为了维护区间 1 1 1 的对数,还需要分别维护住 a , b a,b a,b 串区间内 1 1 1 的个数。

另外因为这个题只进行了一个简单的推平操作,所以我们也不需要写懒节点并将节点信息向下传递,我们只要在线段树节点上打个标记,表示是否推平了,之后修改或者查询的时候查到标记就直接返回就行了。

code:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=1e5+5;int n,q;
string str[2];struct segment_tree{#define ls p<<1#define rs p<<1|1struct Node{int l,r;int a,b;//区间内 a串1的个数,b串1的个数int sam;//ab串同为1的位置的个数bool fa,fb;//是否填平Node(int l=0,int r=0,int a=0,int b=0,int sam=0,bool fa=false,bool fb=false):l(l),r(r),a(a),b(b),sam(sam),fa(fa),fb(fb){}; }tr[maxn<<4];void push_up(int p){auto& [l,r,a,b,sam,fa,fb]=tr[p];a=(fa)?r-l+1:tr[ls].a+tr[rs].a;b=(fb)?r-l+1:tr[ls].b+tr[rs].b;if(fa)sam=tr[p].b;else if(fb)sam=tr[p].a;else sam=tr[ls].sam+tr[rs].sam;}void build(int p,int l,int r){tr[p].l=l;tr[p].r=r;if(l==r){tr[p].a=(str[0][l-1]=='1');tr[p].b=(str[1][l-1]=='1');tr[p].sam=(tr[p].a && tr[p].b);return;}int mid=l+r>>1;build(ls,l,mid);build(rs,mid+1,r);push_up(p);}void print(int p,int l,int r){printf("%d [%d,%d]:%d %d %d\n",p,l,r,tr[p].a,tr[p].b,tr[p].sam);if(l==r){return;}int mid=l+r>>1;print(ls,l,mid);print(rs,mid+1,r);}void print(){print(1,1,n);}void modify(int p,int l,int r,int L,int R,bool st){if(L<=l && r<=R){if(st){//填平a串 tr[p].a=r-l+1;tr[p].fa=true;tr[p].sam=tr[p].b;}else {//填平b串 tr[p].b=r-l+1;tr[p].fb=true;tr[p].sam=tr[p].a;}return;}int mid=l+r>>1;if(mid>=L)modify(ls,l,mid,L,R,st);if(mid<R)modify(rs,mid+1,r,L,R,st);push_up(p);}int q(){return tr[1].sam;}#undef ls#undef rs
}tr;int main(){
//	cin.tie(0)->sync_with_stdio(false);cin>>n>>str[0]>>str[1];tr.build(1,1,n);for(cin>>q;q;q--){char ch;int l,r;cin>>ch>>l>>r;tr.modify(1,1,n,l,r,(ch=='A'));cout<<tr.q()<<endl;
//		tr.print();
//		cout<<endl;}return 0;
}

G 小红不想做平衡树

思路:

我们发现,在一个数列里,数列一定是升序段降序段交替出现的,比如:升序-降序-升序-降序…,或者 降序-升序-降序-升序…。

我们选择一段区间,然后翻转其某个子段,使得反转后成为一个升序序列,有五种可能的情况(因为题目保证了数列中数各不相同,所以这里不讨论数值相等的情况,下面默认如此):

  1. 整段升序。
  2. 整段降序。
  3. 先升序,后降序。而且第一段最大值小于第二段最小值。
  4. 先降序,后升序。而且第一段最大值小于第二段最小值。
  5. 先升序,后降序,再升序。第一段最大值小于第二段最小值,且第二段最大值小于第三段最小值。

大概示例图如下:
在这里插入图片描述

我们对每种情况分别讨论,然后统计答案即可。

不过实际在写的时候会非常麻烦,因为前一段的末尾那个数正好就是后一段开头的那个数,导致上面的五种情况会出现重叠计数的情况。比如第三种情况中,第二段只取第一个数时,统计出来的答案就会和第一种情况完全重复,再比如第五种情况中第一段只选第一个数时统计出来的答案都和第四种情况出现重复等。在官方题解的写法中,细节也是蛮多的。下面只讲我的写法,和题解不太一样。

回到开头,在一个数列里,数列一定是升序段降序段交替出现的,而升序段和降序段交界处的那个数是两段共用的。这种“转折点”有两种类型:升序变降序(形如 ^),降序变升序(形如 √)。而且是交替出现的。

我们可以把这些转折点处理出来,然后根据转折点来统计答案。虽然仍然会出现重复的情况,但是更直观一些(大概?)

code:

#include <iostream>
#include <cstdio>
#include <vector>
#define pii pair<int,int>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;int n,a[maxn];int main(){cin>>n;for(int i=1;i<=n;i++)cin>>a[i];ll ans=0;int st=-1;//第一个 ^ 点的位置vector<int> ver;for(int i=2,f;i<n;i++){f=-1;if(a[i-1]<a[i] && a[i]>a[i+1])f=0;// ^if(a[i-1]>a[i] && a[i]<a[i+1])f=1;// √if(!~st)st=f;if(~f)ver.push_back(i);}int tl=1,len,tn=ver.size();//1 2for(auto i:ver){len=i-tl+1;ans+=1ll*(len+1)*len/2;tl=i;}len=n-tl+1;ans+=1ll*(len+1)*len/2;ans-=tn;for(int i=st,id,l,r;i<ver.size();i+=2){//3id=ver[i];l=(i==0)?1:ver[i-1];r=(i==ver.size()-1)?n:ver[i+1];for(int j=id+1;j<=r;j++){//这边从id+1的位置开始统计,当j=id时会和情况2重复if(a[j]>a[id-1])ans+=id-l;else break;}}for(int i=st^1,id,l,r;i<ver.size();i+=2){//4id=ver[i];l=(i==0)?1:ver[i-1];r=(i==ver.size()-1)?n:ver[i+1];for(int j=id-1;j>=l;j--){//这边从id-1的位置开始统计,当j=id时会和情况1重复if(a[j]<a[id+1])ans+=r-id;else break;}}for(int i=st,id1,id2,l,r;i+1<ver.size();i+=2){//5id1=ver[i];id2=ver[i+1];l=(i==0)?1:ver[i-1];r=(i+1==ver.size()-1)?n:ver[i+2];if(a[id1-1]<a[id2] && a[id1]<a[id2+1])ans+=1ll*(id1-l)*(r-id2);}cout<<ans<<endl;return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/820141.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RT-Thread学习

RT-Thread三个版本——标准版本 RT-Thread&#xff0c;全称是Real Time-Thread&#xff0c;顾名思义&#xff0c;它是一个嵌入式实时多线程操作系统&#xff0c;基本属性之一是支持多任务&#xff1a;一个处理器核心在某一时刻只能运行一个任务&#xff0c;由于每次对一个任务…

HCIP【ospf综合实验】

目录 实验要求&#xff1a; 实验拓扑图&#xff1a; 实验思路&#xff1a; 实验步骤&#xff1a; 一、划分网段 二、配置IP地址 三、搞通私网和公网 &#xff08;1&#xff09;先搞通私网&#xff08;基于OSPF协议&#xff0c;在各个路由器上进行网段的宣告&#xff0c…

实现智能水控 | 基于ACM32 MCU的分体式水控方案

分体式水控概述 分体式水控是一种常见的水控系统&#xff0c;它的工作原理是通过水的流动来控制水的供应和排放&#xff0c;该系统一般由两部分组成&#xff1a;控制器和水阀。控制器负责监测水的流量和压力&#xff0c;根据设定的参数来控制水阀的开和关&#xff0c;从而实现水…

2024认证杯数学建模A题保暖纤维保暖能力原创论文讲解(含完整python代码)

大家好呀&#xff0c;从发布赛题一直到现在&#xff0c;总算完成了认证杯数学中国数学建模网络挑战赛第一阶段A题目保暖纤维的保暖能力完整的成品论文。 本论文可以保证原创&#xff0c;保证高质量。绝不是随便引用一大堆模型和代码复制粘贴进来完全没有应用糊弄人的垃圾半成品…

windows下vscode调试虚拟机linux c++工程的三种方法

vscode去远程调试方法有很多种&#xff0c;不同的插件对应了不同的调试方法&#xff0c;比如&#xff1a; 1.C/C插件进行GDB调试(编写launch.json文件) 2.C/C Runner插件 3.CMake Tools插件&#xff08;只针对CMake工程&#xff0c;需要搭配C/C插件一起使用&#xff0c;但无…

Gin框架小结

Gin 简介 Gin是一个轻量级的Web框架&#xff0c;用于构建高性能的Go语言Web应用程序。提供了路由管理、中间件支持、参数绑定和验证、错误处理、静态文件服务等功能。 Gin框架解决了什么问题和痛点 1.golang http 标准库本身提供了比较简单的路由注册能力&#xff0c;只支持…

记录一次内存溢出

1、查看catalina相关日志&#xff0c;确定关键字相关行号 文件&#xff1a;catalina.out命令1&#xff1a;cat -n catalina.out |grep -a OutOfMemoryError与内存溢出相关的如上&#xff0c;每一个行号其实都对应到具体时间点。可以发现&#xff0c;这个范围相符合&#xff1…

清明三天,用Python赚了4万?

每年4月&#xff0c;是Python圈子里接私活的旺季&#xff0c;特别是在节假日这种数据暴增的时间段&#xff0c;爬虫采集、逆向破解类的私活订单会集中爆发&#xff0c;量大价高。几乎所有的圈内人都在趁着旺季接私活。 正好&#xff0c;我昨天就做了一单爬虫逆向私活&#xff…

引领软件供应链安全 比瓴科技位居安全牛全景图第一

近日&#xff0c;安全牛第十一版《中国网络安全行业全景图》正式发布&#xff0c;比瓴科技入选全景图软件供应链安全赛道中开发流程安全管理、DevSecOps和软件成分分析三个重要细分领域&#xff0c;并位居开发流程安全管控领域第一。 安全牛本次全景图研究工作于23年正式启动&a…

什么是云安全?云安全包含哪些方面?

云计算彻底改变了数据存储的世界&#xff0c;它使企业可以远程存储数据并随时随地从任何位置访问数据。存和取变得简单&#xff0c;也使得云上数据极易造成泄露或者被篡改&#xff0c;所以云安全就显得非常重要了。那么什么是云安全&#xff1f;云安全的工作原理是什么&#xf…

做一个好的程序员难吗?只需要这10个习惯

在这个世界上&#xff0c;有数以百万计的人对软件开发充满热情&#xff0c;他们有很多名字&#xff0c;如软件工程师、程序员、编码员、开发人员。一段时间后&#xff0c;这些人可能会成为一名优秀的编码员&#xff0c;并且他们将非常熟悉如何使用计算机语言完成工作。但是&…

EasyRecovery激活秘钥2024最好用的电脑数据恢复软件下载

EasyRecovery数据恢复软件是一款专业且功能强大的数据恢复工具&#xff0c;它旨在帮助用户从各种存储设备中恢复由于各种原因&#xff08;如误删除、格式化、病毒攻击、系统崩溃等&#xff09;导致丢失的数据。这款软件支持多种存储介质&#xff0c;包括但不限于硬盘驱动器、U盘…

0.5W 3KVDC 隔离 单输出 DC/DC 电源模块 ——TPR-W5 系列

TPR-W5系列是一款需要隔离和电压转换的产品&#xff0c;工业级环境温度&#xff0c;温度范围从–40℃到105℃&#xff0c;用于PCB安装的国际标准结构。此系列产品小巧&#xff0c;效率高&#xff0c;低输出纹波及提供3000V以上的直流电压隔离&#xff0c;用于需要隔离的场合&am…

【Spring系列】- Spring事务底层原理

实验准备 配置文件 首先在配置文件中配置jdbcTemplate和事务管理器&#xff0c;并且需要开启事务的注解EnableTransactionManagement以及Configuration注解 ComponentScan("com.lyd") EnableTransactionManagement Configuration public class ApplicationConfig …

[入门]测试原则-ApiHug准备-测试篇-002

&#x1f917; ApiHug {Postman|Swagger|Api...} 快↑ 准√ 省↓ GitHub - apihug/apihug.com: All abou the Apihug apihug.com: 有爱&#xff0c;有温度&#xff0c;有质量&#xff0c;有信任ApiHug - API design Copilot - IntelliJ IDEs Plugin | Marketplace 写在前面…

低敏猫粮怎么选?看这一篇就够了!

亲爱的朋友们&#xff0c;你们是否曾经为了家中敏感肠胃的小猫咪而犯愁&#xff0c;不知道如何选择适合的猫粮呢&#xff1f;今天&#xff0c;就让我们一起聊聊低敏猫粮与普通猫粮的那些不同之处吧&#xff01;&#x1f431; 1️⃣ **成分差异**&#xff1a;首先&#xff0c;从…

Go 自定义14位时间类型 yyyyMMddHHmmss

目录 功能 代码 功能 数据库或者接口时间类型&#xff0c;经常会使用14位的时间格式。每次都转换有点麻烦。可以自定义一个时间类型。 自定义类型需要实现json接口中的MarshalJSON与UnmarshalJSON两个函数&#xff0c;这样在做json编码解码时就会自动转为14位的时间格式了。…

第四届大数据工程与教育国际会议(BDEE 2024)即将召开!

第四届大数据工程与教育国际会议&#xff08;BDEE 2024&#xff09;将于2024年8月9-11日在泰国清迈举行。数据驱动教育变革&#xff0c;智慧点亮未来课堂&#xff01;BDEE 2024是专注于大数据工程与教育领域的重要学术会议&#xff0c;全球大数据与教育精英齐聚&#xff0c;在数…

使用 Docker 部署 SurveyKing 调查问卷系统

1&#xff09;SurveyKing 介绍 SurveyKing 是一款功能强大、操作简便的开源问卷系统。它不仅满足了用户对问卷调查的基本需求&#xff0c;还提供了丰富的逻辑设置和灵活的问题设置&#xff0c;使得问卷制作更加智能化和个性化。此外&#xff0c;SurveyKing 还具有快速部署和安全…

构建鸿蒙ACE静态库

搭建开发环境 根据说明文档下载鸿蒙全部代码&#xff0c;一般采取第四种方式获取最新代码(请保证代码为最新) 源码获取Windows下载编译环境 MinGW GCC 7.3.0版本 请添加环境变量IDE 可以使用两种 CLion和Qt,CLion不带有环境需要安装MinGW才可以开发,Qt自带MinGW环境&#xff0…