Codeforces Round 919 (Div. 2)补题

2024-01-14 13:52
文章标签 codeforces round div 补题 919

本文主要是介绍Codeforces Round 919 (Div. 2)补题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Satisfying Constraints(Problem - A - Codeforces)

题目大意:有三种限定方式:

1.k>=x;

2.k<=x;

3.k!=x;

根据若干限定,找出合法的k的个数。

思路:通过1,2定出区间,同时记录3中的x,遍历记录的容器,如果x在区间内,那么ans--即可,不要遍历区间,会超时,而且也更麻烦。

#include<bits/stdc++.h>
using namespace std;
int main()
{int t;scanf("%d",&t);while(t--){int n;int l=0,r=1e9+10;vector<int>p;scanf("%d",&n);for(int i=1;i<=n;i++){int op,c;scanf("%d%d",&op,&c);if(op==1) l=max(l,c);else if(op==2) r=min(r,c);else p.push_back(c);	}if(r<l) printf("0\n");else {int ans=r-l+1;for(int i=0;i<p.size();i++){if(l<=p[i]&&p[i]<=r) ans--;}printf("%d\n",ans);}}
}

Summation Game(Problem - B - Codeforces)

题目大意:A和B在玩游戏,现有一个数组a[],A先开始,A每次可以删除最多x个数,B可以将最多y个数全部乘-1,两人分别执行一次操作后求数组和,A想最大化结果,B想最小化结果。两人都发挥最佳状态,问最后的结果是多少。

思路:A的操作实际上是将被操作数a[i]的贡献变成0,B则是将被操作数a[i]的贡献变成-a[i],B想要最小化结果,那么肯定是要将操作数全部用掉,但是对A来说,她的操作,一方面减少了被操作数的贡献,但同时也防止被操作数被B操作,造成更大损失。所以A如果操作就要尽可能挑大的数进行操作,进而削弱B的破坏。B也要尽可能对大的数进行操作,造成更多损失。那么我们只用将数组排序,然后讨论A需要操作多少个即可,为了及时获取她们操作区间的和(因为要将这部分从总和中删掉),用前缀和处理一下。

#include<bits/stdc++.h>
using namespace std;
int c[200010],s[200010];
bool cmp(int x,int y)
{return x>y;
}
int main()
{int t;scanf("%d",&t);while(t--){int n,a,b,sum=0;scanf("%d%d%d",&n,&a,&b);for(int i=1;i<=n;i++) scanf("%d",&c[i]),sum += c[i];sort(c+1,c+1+n,cmp);for(int i=1;i<=n;i++) s[i]=s[i-1]+c[i];int mx=-1e9;for(int i=0,j=i+b;i<=a;i++,j++){if(j>n) j=n;int d=2*(s[j]-s[i])+s[i];int ans=sum-d;mx=max(mx,ans);}printf("%d\n",mx);}
}

Partitioning the Array()

题目大意:现有一个数组a[],我们要将它划分成k份,每份含有的数量是相同的,如果存在一个m,使得用a[i]%m去替换a[i]后,每个划分出来的数组都相同,那么便算作一次有效划分,问共有多少有效划分。

思路:我们很容易发现,划分后对应位置是同余的,即a[i]与a[i+k]是同余的,当然a[i]与a[i+2k]也是同余的,但是我们可以用a[i+1]与a[i+2k]来判断,这样就有递推关系了。则意味着它们的差值的最大公因数非1.核心部分如下:

for(int k=1;k<=n;k++){if(n%k==0){int g=0;for(int i=1;i+k<=n;i++){g=__gcd(g,abs(a[i+k]-a[i]));}if(g!=1) ans++;}}

__gcd()是内置函数,__gcd(0,a)=a

实际上的时间复杂度是小于2*sqrt(n)*n,所以虽然是嵌套循环,但不会超时。

#include<bits/stdc++.h>
using namespace std;
int a[200010];
int main()
{int t;scanf("%d",&t);while(t--){int n,ans=0;scanf("%d",&n);for(int i=1;i<=n;i++) scanf("%d",&a[i]);for(int k=1;k<=n;k++){if(n%k==0){int g=0;for(int i=1;i+k<=n;i++){g=__gcd(g,abs(a[i+k]-a[i]));}if(g!=1) ans++;}}printf("%d\n",ans);}
}

Array Repetition(Problem - D - Codeforces)

题目大意:现有一个空数组a[]和两种操作:

1.将x插入到数组末尾

2.将整个数组复制x次接到数组末尾。

按照规定顺序进行操作,最后有q个查询,查询指定位置的数是多少。

1<n,q<1e5,b={1,2},b=1:1<=x<=n;b=2,1<=x<=1e9,查询下标k:1<=k<=min(c,1e18),c是完成所有操作后的数组长度。

思路:这道题肯定不能直接模拟,数据范围太大了,我们注意到对于复制部分需要到被复制部分去找,所以首先哪些部分是由复制得到的需要记录下来。最关键的就是怎么记录这些数据,而且还要区分哪些是插入的,哪些是复制的。有一个思路就是,通过记录每次操作来实现。我们首先定义一个dp[]数组来记录当前操作结束后数组最后一个元素的下标,另外还得定义一个数组来记录最后一个元素的值。和一个可以存放哪些操作是复制操作的容器。比如我们通过容器知道i操作是复制操作,就可以通过dp[i]知道复制区间的右界,同时dp[i-1]就是复制区间的左界(并不是恰好取到,而是定出范围),这样对于一个k,我们通过遍历容器,就可以知道它是否在复制区间内,如果在复制区间内,我们可以通过取模运算将它转到插入部分。通过对dp数组的查找,我们就可以获得它对应的插入部分的位置是在第几次操作时进行插入的,而每次插入的值我们是记录了的,就可以由此得到位置k的数值。

以上只是一个总体的思路,还有许多细节部分需要一一处理清楚:

1.dp的赋值,dp是用来记录第i次操作结束后,数组中最后一个元素的下标的,所以当执行插入操作时,dp[i]=dp[i-1]+1,当执行复制操作时dp[i]=dp[i-1]*(x+1),另外,因为我们的查询范围在1e18以内,所以大于1e18的位置可以不记录了,但是为了统一,我们直接将位置大于1e18的全部记录成一个大于1e18的数,当然可以直接统一成2e18也可以。

2.v[]的计算,v存的是第i次操作结束后,数组中最后一个位置的值,执行插入操作是,很显然v[i]=x,执行复制操作的话v[i]=v[i-1].

3.对容器p的遍历,因为我们容器中存的是复制对应的操作位置i,那么dp[i]就可以得到这个复制操作执行完后,最右端的位置,dp[i-1]+1就是这个复制区间的左端点,但是因为dp[i]和dp[i-1]对应位置的值在v[]中都有记录,如果k在这两个位置,那么我们就不进行处理,可以直接去找值,如果不是,那么k就要转化,转化操作为k%dp[i-1],因为dp[i-1]是前面被复制区间的长度,所以这样就可以得到k位置在被复制区间中的位置。然后再不断的找。因为可能有多次复制操作,所以我们从后往前访问,因为k可能需要不断往前转化,当然,这里是有特殊情况的,就是当k%dp[i-1]==0的时候,直接让k=dp[i-1],然后退出,因为k肯定不能为0。

4.k确定后去查找值,k确定后,我们就可以在dp数组中找到这个值,而这个值对应的下标就是操作数,我们可以通过下标获取每次操作的值,也就是该位置的值。这里在dp中查找最好用lower_bound,因为我们的k通过转化,肯定是对应着dp中某一个确定的值的,所以肯定可以找到,find()的时间复杂度是O(n),而lower_bound()的时间复杂度是O(logn),更快一些。

至此,本题解决。

核心思想就是,通过操作次数的下标将dp[]和v[]联系起来,然后利用容器和dp来判断查找位置是否是复制位置,如果是复制位置,那么就要转化到非复制位置去,然后利用dp[]和v[]的联系找出该位置的值。这里有个查找值是否在特殊区间中的方法就是,记录一个端点的位置然后用被记录端点表示出另一个端点,进而得到区间的范围,我们只需要遍历记录一个端点位置的容器即可。当然分别记录左右端点的位置,然后在两个容器中二分查找也可以,但是本题涉及到不断转化,前一种方法好。

#include<bits/stdc++.h>
using namespace std;
long long dp[100010];
int v[100010];
int main()
{int t;scanf("%d",&t);while(t--){int n,q;scanf("%d%d",&n,&q);vector<int>p;int flag=1;for(int i=1;i<=n;i++){int op,x;scanf("%d%d",&op,&x);if(op==1) {v[i]=x;dp[i]=dp[i-1]+1;}else{v[i]=v[i-1];if(dp[i-1]>=2e18/(x+1)) dp[i]=2e18;else dp[i]=dp[i-1]*(x+1);if(flag) p.push_back(i);}if(dp[i]==2e18) flag=0;}while(q--){long long x;scanf("%lld",&x);for(int i=p.size()-1;i>=0;i--){int j=p[i];if(dp[j-1]<x&&x<dp[j]){if(x%dp[j-1]==0){x=dp[j-1];break;}x%=dp[j-1];}}int ve=v[(lower_bound(dp+1,dp+1+n,x)-dp)];printf("%d ",ve);}printf("\n");}
}

ps:另外要注意2e18是double类型的数,与long long类型的数进行==比较的时候,编译器会自动进行类型提升,但是进行>=时,是会报错的。

这篇关于Codeforces Round 919 (Div. 2)补题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/605395

相关文章

Codeforces Round #240 (Div. 2) E分治算法探究1

Codeforces Round #240 (Div. 2) E  http://codeforces.com/contest/415/problem/E 2^n个数,每次操作将其分成2^q份,对于每一份内部的数进行翻转(逆序),每次操作完后输出操作后新序列的逆序对数。 图一:  划分子问题。 图二: 分而治之,=>  合并 。 图三: 回溯:

Codeforces Round #261 (Div. 2)小记

A  XX注意最后输出满足条件,我也不知道为什么写的这么长。 #define X first#define Y secondvector<pair<int , int> > a ;int can(pair<int , int> c){return -1000 <= c.X && c.X <= 1000&& -1000 <= c.Y && c.Y <= 1000 ;}int m

Codeforces Beta Round #47 C凸包 (最终写法)

题意慢慢看。 typedef long long LL ;int cmp(double x){if(fabs(x) < 1e-8) return 0 ;return x > 0 ? 1 : -1 ;}struct point{double x , y ;point(){}point(double _x , double _y):x(_x) , y(_y){}point op

Codeforces Round #113 (Div. 2) B 判断多边形是否在凸包内

题目点击打开链接 凸多边形A, 多边形B, 判断B是否严格在A内。  注意AB有重点 。  将A,B上的点合在一起求凸包,如果凸包上的点是B的某个点,则B肯定不在A内。 或者说B上的某点在凸包的边上则也说明B不严格在A里面。 这个处理有个巧妙的方法,只需在求凸包的时候, <=  改成< 也就是说凸包一条边上的所有点都重复点都记录在凸包里面了。 另外不能去重点。 int

Codeforces 482B 线段树

求是否存在这样的n个数; m次操作,每次操作就是三个数 l ,r,val          a[l] & a[l+1] &......&a[r] = val 就是区间l---r上的与的值为val 。 也就是意味着区间[L , R] 每个数要执行 | val 操作  最后判断  a[l] & a[l+1] &......&a[r] 是否= val import ja

CSS实现DIV三角形

本文内容收集来自网络 #triangle-up {width: 0;height: 0;border-left: 50px solid transparent;border-right: 50px solid transparent;border-bottom: 100px solid red;} #triangle-down {width: 0;height: 0;bor

创建一个大的DIV,里面的包含两个DIV是可以自由移动

创建一个大的DIV,里面的包含两个DIV是可以自由移动 <body>         <div style="position: relative; background:#DDF8CF;line-height: 50px"> <div style="text-align: center; width: 100%;padding-top: 0px;"><h3>定&nbsp;位&nbsp;

Codeforces Round 971 (Div. 4) (A~G1)

A、B题太简单,不做解释 C 对于 x y 两个方向,每一个方向至少需要 x / k 向上取整的步数,取最大值。 由于 x 方向先移动,假如 x 方向需要的步数多于 y 方向的步数,那么最后 y 方向的那一步就不需要了,答案减 1 代码 #include <iostream>#include <algorithm>#include <vector>#include <string>

CF#271 (Div. 2) D.(dp)

D. Flowers time limit per test 1.5 seconds memory limit per test 256 megabytes input standard input output standard output 题目链接: http://codeforces.com/contest/474/problem/D We s

CF #278 (Div. 2) B.(暴力枚举+推导公式+数学构造)

B. Candy Boxes time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output 题目链接: http://codeforces.com/contest/488/problem/B There