Codeforces Round #613 (Div. 2)
A. Mezo Playing Zoma (CF 1285 A)
题目大意
机器人初始位置为,给了一串指令告诉机器人是往左走一格还是右走一格,部分指令可能会丢失,问机器人最终可能的位置的情况数。
解题思路
的个数加一即为答案。
神奇的代码
#include <bits/stdc++.h> using namespace std; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); int n; string s; cin>>n>>s; int l=0,r=0; for(int i=0;i<n;++i){ if (s[i]=='L') ++l; else ++r; } int ans=l+r+1; cout<<ans<<endl; }
B. Just Eat It! (CF 1285 B)
题目大意
给定一个数列,问整个区间和以及部分区间和哪个大。
解题思路
区间和最值的用,特判最值是否在全部区间取的即可。表示前个数,其中第个数必取的最大值。则,答案为。
对应为代码注释部分。
注意到区间可以理解为是去掉从开头的连续几个数以及从结尾的连续几个数。去掉后如果和会变大或者不变,则说明存在某点的前缀和或后缀和小于等于,如此两边扫一遍也行。
神奇的代码
#include <bits/stdc++.h> #define MIN(a,b) ((((a)<(b)?(a):(b)))) #define MAX(a,b) ((((a)>(b)?(a):(b)))) #define ABS(a) ((((a)>0?(a):-(a)))) using namespace std; typedef long long LL; typedef vector<int> VI; typedef pair<int,int> PII; typedef vector<PII> VPII; typedef vector<LL> VL; typedef pair<LL,LL> PLL; typedef vector<PLL> VPLL; template <typename T> void read(T &x) { int s = 0, c = getchar(); x = 0; while (isspace(c)) c = getchar(); if (c == 45) s = 1, c = getchar(); while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar(); if (s) x = -x; } template <typename T> void write(T x, char c = ' ') { int b[40], l = 0; if (x < 0) putchar(45), x = -x; while (x > 0) b[l++] = x % 10, x /= 10; if (!l) putchar(48); while (l) putchar(b[--l] | 48); putchar(c); } const int N=1e5+8; int n; LL a[N]; bool check(){ LL sum=0; for(int i=0;i<n;++i){ sum+=a[i]; if (sum<=0) return 0; } sum=0; for(int i=n-1;i>=0;--i){ sum+=a[i]; if (sum<=0) return 0; } return 1; } int main(void) { //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); int kase; read(kase); for (int i = 1; i <= kase; i++) { //printf("Case #%d: ", i); read(n); for(int i=0;i<n;++i) read(a[i]); if (check()) puts("YES"); else puts("NO"); } return 0; } /* int main(void) { //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); int kase; read(kase); for (int i = 1; i <= kase; i++) { //printf("Case #%d: ", i); int n; LL sum=0; read(n); LL a[n+5]={0}; for(int i=0;i<n;++i){ read(a[i]); sum+=a[i]; } LL ans=a[0]; LL dp[n+5]={0}; dp[0]=a[0]; bool qwq=true; for(int i=1;i<n;++i){ if (dp[i-1]+a[i]>a[i]) dp[i]=dp[i-1]+a[i]; else {dp[i]=a[i]; qwq=false;} ans=MAX(ans,dp[i]); } if (qwq) for(int i=0;i<n-1;++i) if (dp[i]==sum) qwq=false; if (dp[n-1]==sum&&qwq&&ans==sum) ans=sum-1; if (ans>=sum) printf("NO\n"); else printf("YES\n"); } return 0; } */
C. Fadi and LCM (CF 1285 C)
题目大意
给定,找出一对使得且最小。
解题思路
,令,则,不失一般性,我们设即,我们要最小化,即最小化,即最大化,即找到最大的且,由于,而,所以我们从大到小枚举判断是否等于即可。我们也可以假设,这是始终有解且一定是最小的。
神奇的代码
#include <bits/stdc++.h> #define MIN(a,b) ((((a)<(b)?(a):(b)))) #define MAX(a,b) ((((a)>(b)?(a):(b)))) #define ABS(a) ((((a)>0?(a):-(a)))) using namespace std; typedef long long LL; typedef vector<int> VI; typedef pair<int,int> PII; typedef vector<PII> VPII; typedef vector<LL> VL; typedef pair<LL,LL> PLL; typedef vector<PLL> VPLL; template <typename T> void read(T &x) { int s = 0, c = getchar(); x = 0; while (isspace(c)) c = getchar(); if (c == 45) s = 1, c = getchar(); while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar(); if (s) x = -x; } template <typename T> void write(T x, char c = ' ') { int b[40], l = 0; if (x < 0) putchar(45), x = -x; while (x > 0) b[l++] = x % 10, x /= 10; if (!l) putchar(48); while (l) putchar(b[--l] | 48); putchar(c); } int main(void) { //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); LL x=0; read(x); LL qwq=sqrt(x); while(qwq){ if (x%qwq==0) if(__gcd(qwq,x/qwq)==1) break; --qwq; } printf("%lld %lld\n",qwq,x/qwq); return 0; }
D. Dr. Evil Underscores (CF 1285 D)
题目大意
给定个数,要求找一个数,最小化。输出这个最小值。
解题思路
异或题盲猜trie
然后弄dp然后暴毙
经过分析我们发现,对于在二进制下的某一位,如果全都是或者,我们都可以对在这一位添或来变小,但如果某一位既有又有,那这一位将不可避免的存在。那么我们从高位起,判断该位,如果全部是或,那么答案在该位就是,否则将是,然后分在该位是或两种情况继续搜下去即可。在树上跑。
神奇的代码
#include <bits/stdc++.h> #define MIN(a,b) ((((a)<(b)?(a):(b)))) #define MAX(a,b) ((((a)>(b)?(a):(b)))) #define ABS(a) ((((a)>0?(a):-(a)))) using namespace std; typedef long long LL; typedef vector<int> VI; typedef pair<int,int> PII; typedef vector<PII> VPII; typedef vector<LL> VL; typedef pair<LL,LL> PLL; typedef vector<PLL> VPLL; template <typename T> void read(T &x) { int s = 0, c = getchar(); x = 0; while (isspace(c)) c = getchar(); if (c == 45) s = 1, c = getchar(); while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar(); if (s) x = -x; } template <typename T> void write(T x, char c = ' ') { int b[40], l = 0; if (x < 0) putchar(45), x = -x; while (x > 0) b[l++] = x % 10, x /= 10; if (!l) putchar(48); while (l) putchar(b[--l] | 48); putchar(c); } const int N=4e6+7; int trie[N][2],n,m=1; void add(int x){ int t=1; for(int i=29;i>=0;--i){ if (!trie[t][(x>>i)&1]) trie[t][(x>>i)&1]=++m; t=trie[t][(x>>i)&1]; } } int DFS(int t,int len){ if (len<0) return 0; if (!trie[t][0]) return DFS(trie[t][1],len-1); if (!trie[t][1]) return DFS(trie[t][0],len-1); return (min(DFS(trie[t][0],len-1),DFS(trie[t][1],len-1))|(1<<len)); } int main(void) { //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); read(n); for(int u,i=1;i<=n;++i){ read(u); add(u); } printf("%d\n",DFS(1,29)); return 0; }
E. Delete a Segment (CF 1285 E)
题目大意
给定条线段,线段之间若有交叉(端点值相同也算交叉)或者重合则可以联合起来成为新的一条(可能)更长的线段,现在要求去掉一条线段(不能不去),使得去掉后联合后的线段最多,问是多少。
解题思路
我们考虑去掉一条线段后能够增加多少个线段。
我们可以发现,如果该线段所覆盖的区间里,存在某个子区间,它只被该线段覆盖的话,去掉该线段后,这里就有一个空隙。而如果有个空隙出来的话,那就会多出个线段出来。这启示我们从空隙数量的角度来解决联合线段的个数。
我们考虑如何求只被该线段覆盖的区间的数量。
我们按左端点从小到大排列枚举,对于当前枚举的这条线段,前条线段的右端点的最大值为,次大值为,则对于其右端点为的某条线段来说,它所覆盖的区间中,区间(或,如果)并没有被其他线段覆盖,如果第条线段的左端点的话,那么区间这部分区间就只被线段覆盖,然后我们更新及重复操作,得到每条线段覆盖的区间内没被其他线段覆盖的区间数(或者说线段内的空隙),还有本身存在的空隙,最后由植树原理得答案。
要特判全部线段没有交叉的情况,此时最终答案应是。
神奇的代码
#include <bits/stdc++.h> #define MIN(a,b) ((((a)<(b)?(a):(b)))) #define MAX(a,b) ((((a)>(b)?(a):(b)))) #define ABS(a) ((((a)>0?(a):-(a)))) using namespace std; typedef long long LL; typedef vector<int> VI; typedef pair<int,int> PII; typedef vector<PII> VPII; typedef vector<LL> VL; typedef pair<LL,LL> PLL; typedef vector<PLL> VPLL; template <typename T> void read(T &x) { int s = 0, c = getchar(); x = 0; while (isspace(c)) c = getchar(); if (c == 45) s = 1, c = getchar(); while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar(); if (s) x = -x; } template <typename T> void write(T x, char c = ' ') { int b[40], l = 0; if (x < 0) putchar(45), x = -x; while (x > 0) b[l++] = x % 10, x /= 10; if (!l) putchar(48); while (l) putchar(b[--l] | 48); putchar(c); } int main(void) { //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); int kase; read(kase); for (int i = 1; i <= kase; i++) { //printf("Case #%d: ", i); int n; vector<pair<int,int>> a; read(n); for(int l,r,i=0;i<n;++i){ read(l); read(r); a.push_back(make_pair(l,r)); } sort(a.begin(),a.end(),less<pair<int,int>>()); int r=a[0].second,ans=0,ma=-2147483644,cnt=0,gap=0; for(int i=1;i<n;++i){ if (a[i].first>r){ ++gap; r=a[i].second; ma=-2147483644; ans=max(ans,cnt); cnt=0; }else if (ma==-2147483644){ ma=min(r,a[i].second); r=max(r,a[i].second); }else{ if (a[i].first>ma) ++cnt; if (a[i].second>=r){ ans=max(ans,cnt); cnt=0; } ma=max(ma,min(r,a[i].second)); r=max(r,a[i].second); } } ans=max(ans,cnt); ans=ans+gap+1; if (gap+1==n) ans=n-1; printf("%d\n",ans); } return 0; }
F. Classical? (CF 1285 F)
题目大意
给定个数,求。
解题思路
。我们可以枚举,然后所有数都除以,这样我们要寻找的就是两个互质的数,它们的乘积最大。我们从大到小遍历这些数,对于当前的数,我们想知道大于它的数中是否有与它互质的,即求是否大于零。这是个经典式子,由于,我们对其变形:
我们改变它的求和顺序,由于肯定是的因子,我们枚举它的每一个因子,这样的因子在求和式中出现次数为,得
其中表示大于的数中是的倍数的个数,是莫比乌斯函数。
这样我们维护一个数组,就能够知道是否有与互质的数,拿一个指针往回扫,扫到那个互质的数,然后计算答案(因为这里的两个数都除以了一次)。注意下次再遇到有互质的时候,指针从上次的位置继续往回找即可,不需要重新回到原来位置往回扫,因为我们是从大到小遍历这些数,小的数与前面的数的乘积不可能大于原先的答案,这里可以用栈处理。
时间复杂度为,其中。
还可以再优化一下,我们把视为,于是把的每个因子都储存下来,这样虽然会增加原本不应有的答案,但这些答案会小于对应的答案,对我们要找的最大值无影响。
也就是说我们对于每个,把它的因子全部加到数组里,因为拿与另一个数求不会小于拿它的某个因子与另一个数求,所以这对最终答案没有影响,尽管会增加原本不会出现的答案。然后再从大到小枚举,寻找比大的且与互质的数,这仍是上面的方法,只是省去了枚举的操作,最终的时间复杂度为
神奇的代码
#include <bits/stdc++.h> #define MIN(a,b) ((((a)<(b)?(a):(b)))) #define MAX(a,b) ((((a)>(b)?(a):(b)))) #define ABS(a) ((((a)>0?(a):-(a)))) using namespace std; template <typename T> void read(T &x) { int s = 0, c = getchar(); x = 0; while (isspace(c)) c = getchar(); if (c == 45) s = 1, c = getchar(); while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar(); if (s) x = -x; } template <typename T> void write(T x, char c = ' ') { int b[40], l = 0; if (x < 0) putchar(45), x = -x; while (x > 0) b[l++] = x % 10, x /= 10; if (!l) putchar(48); while (l) putchar(b[--l] | 48); putchar(c); } const int N=1e5+8; bool sign[N]; int n,ma,u[N],cnt[N]; LL ans; vector<int> d[N]; stack<LL> s; void pre(){ for(int i=1;i<=ma;++i){ for(int j=i;j<=ma;j+=i) d[j].push_back(i); if (i==1) u[i]=1; else if (i/d[i][1]%d[i][1]==0) u[i]=0; else u[i]=-u[i/d[i][1]]; } } int coprime(int x){ int tmp=0; for(int i:d[x]) tmp+=u[i]*cnt[i]; return tmp; } void updata(int x,int val){ for(int i:d[x]) cnt[i]+=val; } int main(void) { //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); read(n); for(int a,i=1;i<=n;++i){ read(a); sign[a]=true; ma=MAX(ma,a); } pre(); for(int i=1;i<=ma;++i) for(int j=2;i*j<=ma;++j) sign[i]|=sign[i*j]; for(int qwq,i=ma;i>=1;--i){ if (!sign[i]) continue; qwq=coprime(i); while(qwq){ if (__gcd(s.top(),(LL)i)==1){ ans=max(s.top()*(LL)i,ans); --qwq; } updata(s.top(),-1); s.pop(); } updata(i,1); s.push((LL)i); } write(ans,'\n'); return 0; }
本文作者:~Lanly~
本文链接:https://www.cnblogs.com/Lanly/p/12181097.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现