2020-01-30 15:43阅读: 281评论: 0推荐: 1

Educational Codeforces Round 81 (Rated for Div. 2)

A. Display The Number (CF 1295 A)

题目大意

n个火柴棒,问摆出的最大数字是多少?摆出每个数字所需要的火柴棒参照红绿灯。
红绿灯

解题思路

贪心即可。不断放1,最后如果剩下一个火柴棒则最高位变成7

神奇的代码
#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)

题目大意

给定一个01s,串t由串s不断重复得到,是无限长的。定义函数f(x)=cnt0(x)cnt1(x),其中cnt0(x)表示串t第一位到第x0的个数,cnt1同理。给定一个数x,问有多少个i使得f(i)=x,无限则输出1

解题思路

由于s串是t串不断重复得到,x=f(j)=kf(n)+f(i),其中k=jn,i=j%n,%是求余,且f(0)=0,所以k=xf(i)f(n),对于每一个i[1,n],我们只要判断是否(xf(i))f(n)>0(xf(i))%f(n)==0即可。当f(n)0f(1)f(n)中存在等于x的则答案无限。注意如果x=0的话还要加上一开始的空串。

神奇的代码
#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)

题目大意

给定两个串s,t,构造一个串z等于t,每次取s的子串加到z串的最后,问最少取多少次s的子串。子串是指去掉s串任意个字母,在不改变剩下字母的相对位置得到的串。无法构造输出1

解题思路

set储存s串中每个字母的位置,记录当前处理的串s的位置,模拟就好了。当t串有s串中不存在的字母则不可构造。

神奇的代码
#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)

题目大意

给定a,m,求x=0m1[gcd(a,m)=gcd(a+x,m)]

解题思路

gcd(a,m)=n,则a=k1×n,m=k2×n,若gcd(a,m)=gcd(a+x,m),则a+x=k1×n+x=k3×n,且gcd(k3,k2)=1,即k3k2互质,其中k1k3a+m1x。那问题就转化成给定一个数m,求区间[a,b]有多少个数与m互质,容斥即可。
当然i=1a[gcd(i,m)=1]=d|mμ(d)×ad莫比乌斯或许也可以

神奇的代码
#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)

题目大意

给定一个排列p,和一个数组a表示这个排列的每个位置的能量值,要求从中间某个位置把排列分成左右两段,然后把左边的一些数移动到右边,右边的一些数移动到左边,使得左边的所有值小于右边的所有值。某个值移动的代价为该位置的能量值。求满足条件所需要的最小能量值。注意,如果有一边没有数,我们也认为这满足了上述的条件(前提假则整个命题为真嘛)。

解题思路

我们首先发现,如果左边一段的数的个数是确定的,假设是k,则最终左边的数一定是1k,右边的数一定是k+1n,那么我们先枚举左边一段的数的个数k,然后再枚举分割点i(表示第i个数的右边分割),再计算需要的能量值ans=jiqj>kaj+j>iqjkaj,时间复杂度O(n3)

但我们注意到分割点移动的时候,只有分割点右边一个数对答案的贡献改变,于是可以O(1)更新答案,时间复杂度O(n2)

仔细分析可以发现,当k增加时,只有一个数,即k+1的归宿才从右边移动到左边,其他数都不变,那我们考虑这个数的归宿改变对答案的影响,可以发现,对于分割点在它左边的答案要增加它的能量值ak+1,以让它从右边移动到左边,而分割点在它右边的答案要减去它的能量值ak+1,以消除原来让它从左边移动到右边的所需要的能量。区间修改,用线段树维护答案即可。时间复杂度O(nlog2n)

神奇的代码
#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 中国大陆许可协议进行许可。

posted @   ~Lanly~  阅读(281)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.