Educational Codeforces Round 81 (Rated for Div. 2)
A. Display The Number (CF 1295 A)
题目大意
给个火柴棒,问摆出的最大数字是多少?摆出每个数字所需要的火柴棒参照红绿灯。
解题思路
贪心即可。不断放,最后如果剩下一个火柴棒则最高位变成。
神奇的代码
#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) { int kase; read(kase); for (int i = 1; i <= kase; i++) { int n; read(n); int a[100500]={0}; int cnt=-1; while(n>=2){ a[++cnt]=1; n-=2; } if (n==1) a[cnt]=7; for(int i=cnt;i>=0;--i) putchar(a[i]+'0'); puts(""); } return 0; }
B. Infinite Prefixes (CF 1295 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); } int main(void) { int kase; read(kase); for (int i = 1; i <= kase; i++) { int n; LL x; read(n); read(x); char s[n]={0}; LL sum[n]={0}; scanf("%s",s); sum[0]=(s[0]=='0')?1:-1; bool qwq=sum[0]==x?true:false; for(int i=1;i<n;++i) { sum[i]=sum[i-1]+((s[i]=='0')?1:-1); if (sum[i]==x) qwq=true; } if (sum[n-1]==0&&qwq) {puts("-1"); continue;} else if (sum[n-1]==0&&!qwq) {puts("0"); continue;} if (x*sum[n-1]<0&&!qwq) {puts("0"); continue;} LL ans=0; for(int i=0;i<n;++i){ if ((x-sum[i])*sum[n-1]<0) continue; if ((x-sum[i])%sum[n-1]==0) ans++; } if (x==0) ++ans; write(ans,'\n'); } return 0; }
C. Obtain The String (CF 1295 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); } const int N=1e5+8; char s[N],t[N]; int main(void) { int kase; read(kase); for (int i = 1; i <= kase; i++) { set<int> pos[26]; scanf("%s%s",s,t); int ls=strlen(s); bool sign[27]={0}; for(int i=0;i<ls;++i) pos[s[i]-'a'].insert(i),sign[s[i]-'a']=1; int ans=1,cur=-1; int lt=strlen(t); bool qwq=true; for(int i=0;i<lt;++i){ int x=t[i]-'a'; if (sign[x]==false) {qwq=false; break;} auto a=pos[x].upper_bound(cur); if (a==pos[x].end()){ ans++; cur=(*pos[x].begin()); }else cur=*a; } if (qwq) write(ans,'\n'); else puts("-1"); } return 0; }
D. Same GCDs (CF 1295 D)
题目大意
给定,求。
解题思路
设,则,若,则,且,即与互质,其中。那问题就转化成给定一个数,求区间有多少个数与互质,容斥即可。
当然莫比乌斯或许也可以
神奇的代码
#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); } vector<LL> prim; LL a,m; void divide(LL x){ prim.clear(); int qwq=sqrt(x); for(int i=2;i<=qwq;++i) if (x%i==0){ prim.push_back(i); while(x%i==0) x/=i; } if (x>1) prim.push_back(x); } LL solve(LL x){ vector<LL> que; que.push_back(-1); for(size_t i=0;i<prim.size();++i){ int k=que.size(); for(int j=0;j<k;++j) que.push_back(prim[i]*que[j]*(-1)); } LL ans=0; for(size_t i=1;i<que.size();++i) ans+=x/que[i]; return x-ans; } int main(void) { int kase; read(kase); for (int i = 1; i <= kase; i++) { read(a); read(m); LL x=__gcd(a,m); LL u=(a+m-1)/x; a/=x; m/=x; divide(m); LL ans=solve(u)-solve(a-1); write(ans,'\n'); } return 0; }
~~讲个笑话我内存0 B~~
E. Permutation Separation (CF 1295 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); } const int N=2e5+8; struct Segment_Tree{ #define lson root<<1 #define rson root<<1|1 LL mark[4*N],minn[4*N]; void build(int root,int l,int r,LL *sum){ if (l==r){ minn[root]=sum[l]; mark[root]=0; return; } int mid=(l+r)>>1; build(lson,l,mid,sum); build(rson,mid+1,r,sum); minn[root]=min(minn[lson],minn[rson]); mark[root]=0; } void pushdown(int root){ mark[lson]+=mark[root]; mark[rson]+=mark[root]; minn[lson]+=mark[root]; minn[rson]+=mark[root]; mark[root]=0; } void updata(int root,int l,int r,int ll,int rr,LL x){ if (ll>rr) return; if (ll<=l&&r<=rr){ minn[root]+=x; mark[root]+=x; return; } pushdown(root); int mid=(l+r)>>1; if (ll<=mid) updata(lson,l,mid,ll,rr,x); if (rr>mid) updata(rson,mid+1,r,ll,rr,x); minn[root]=min(minn[lson],minn[rson]); } LL getans(int root,int l,int r,int ll,int rr){ if (ll<=l&&r<=rr) return minn[root]; pushdown(root); int mid=(l+r)>>1; if (rr<mid) return getans(lson,l,mid,ll,rr); else if (ll>=mid) return getans(rson,mid+1,r,ll,rr); else return min(getans(lson,l,mid,ll,rr),getans(rson,mid+1,r,ll,rr)); } }Segment; int n; int pos[N]; LL sum[N],a[N]; int main(void) { read(n); for(int u,i=1;i<=n;++i){ read(u); pos[u]=i; } for(int i=1;i<=n;++i){ read(a[i]); sum[i]=a[i]+sum[i-1]; } Segment.build(1,1,n-1,sum); LL ans=Segment.getans(1,1,n-1,1,n-1); for(int i=1;i<=n;++i){ Segment.updata(1,1,n-1,1,pos[i]-1,a[pos[i]]); Segment.updata(1,1,n-1,pos[i],n-1,-a[pos[i]]); ans=min(ans,Segment.getans(1,1,n-1,1,n-1)); } write(ans,'\n'); return 0; }
本文作者:~Lanly~
本文链接:https://www.cnblogs.com/Lanly/p/12242917.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步