AtCoder Beginner Contest 136

AtCoder Beginner Contest 136

Contest Duration : 2019-08-04(Sun) 20:00 ~ 2019-08-04(Sun) 21:40

WebsiteAtCoder BC-136

后面几题都挺考思考角度D。

C - Build Stairs

题目描述:

有n座山从左到右排列,给定每一座山的高度\(Hi\),现在你可以对每座山进行如下操作至多一次:将这座山的高度降低1。

问是否有可能通过对一些山进行如上操作,使得最后从左至右,山的高度呈不下降序列。若可以输出"Yes",否则输出"No"

数据范围:

\(1<=N<=10^5\),\(1<=Hi<=10^9\)

题解:

我们可以将问题进行转化:

现在有两个序列A,B,满足B[i]=A[i]-1 (i∈[1,n])

问能否构造一个新的序列C,使得C满足如下条件:

  • 对于任意i∈[1,n],C[i]=A[i] 或者 C[i]=B[i]
  • C为不降序列

那很明显在考虑C[i]时,在满足大于等于C[i-1]的前提下,我们选择较小的B[i];否则必须选择A[i]。如果题目将降1改成降k,做法也是一样的。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,a[N],b[N];
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),b[i]=a[i]-1;
    a[n+1]=1e9+1;
    int lst=0;
    for(int i=1;i<=n;i++){
        if(b[i]>=lst)lst=b[i];
        else if(a[i]>=lst)lst=a[i];
        else{puts("No");return 0;}
    }
    puts("Yes");
}

D - Gathering Children

题目描述:

有n个排成一列的方格,每个方格上都写有‘L‘‘R‘,用一个长度为n的字符串表示(下标从1开始),且规定s[1]=‘R‘,s[n]=‘L‘

一开始每个方格上都站了1个小朋友,每个人都会进行\(10^{100}\)次下述移动:

  • 如果此时他站的位置写有L,则他向这个方格的左边移动;反之,向右移动。

问最后每个方格上站了多少个小朋友。

数据范围:

\(2<=n<=10^5\)

样例:

输入样例#1

RRLRL

输出样例#1

0 1 2 1 1

输入样例#2

RRRLLRLLRRRLLLLL

输出样例#2

0 0 3 2 0 2 1 0 0 0 4 4 0 0 0 0
题解:

还是跟思考的角度有关。一开始将所有小朋友视为整体,打了表发现会有循环,但是要想确定\(10^{100}\)次后的答案的话并不是很可做。

考虑将每个小朋友独立开来,单独统计他会贡献给谁。很容易发现一个规律:每个人最后一定会在‘RL‘间循环移动。那就用O(N)的时间预处理出对于每个点i,i的左边离他最近的‘R‘的位置\(R[i]\),i的右边离他最近的‘L‘位置\(L[i]\)。

统计答案时,如果一个点是‘L‘,那这个点上的小朋友最后一定会在\(R[i]\)和\(R[i]+1\)间移来移去,只用考虑\(10^{100}\)的奇偶性即可。如果这个点是‘R‘操作也类似。总之只跟\(10^{100}\)的奇偶性有关,之前还想了很久同余quq

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int R[N],L[N];
int cnt[N];
char s[N];
int main(){
    scanf("%s",s+1);
    int n=strlen(s+1),pos=0;
    for(int i=1;i<=n;i++){
        if(s[i]=='R')pos=i;
        R[i]=pos;
    }
    pos=n;
    for(int i=n;i>=1;i--){
        if(s[i]=='L')pos=i;
        L[i]=pos;
    }
    for(int i=1,step;i<=n;i++){
        if(s[i]=='L'){
            step=i-R[i];
            cnt[R[i]+step%2]++;
        }
        else{
            step=L[i]-i;
            cnt[L[i]-step%2]++;
        }
    }
    for(int i=1;i<=n;i++)printf("%d ",cnt[i]);
}

E - Max GCD

题目描述:

有一个含n个元素的序列A。你可以进行如下操作\([0,k]\)次:

  • 任意选择\(i,j∈[1,n]且i≠j\),操作后:\(Ai=Ai+1,Aj=Aj-1\)(这意味着可能会出现负数)

请你求出最大的正整数ans,使得对于任意Ai都有\(Ai=x*ans (x为任意整数)\)

数据范围&输入输出格式:
  • \(2≤N≤500\)
  • \(1≤Ai≤10^6\)
  • \(0≤K≤10^9\)
  • All values in input are integers.
样例:

输入样例#1

2 3
8 20

输出样例#1

7

输入样例#2

4 5
10 1 2 22

输出样例#2

7
题解:

根据题意,得出如下等式——其中xi表示对Ai进行操作的增加值\((xi∈[-k,k])\)

\(A1+x1=ans*z1\)

\(A2+x2=ans*z2\)

\(......\)

\(An+xn=ans*zn\)

所有等式累加得:

\((A1+A2+..+An)+..(x1+x2+..+xn)=ans*(z1+z2+..+zn)\)

由于所有x累加后和为0,故ans必为A序列的总和的因数。基本框架可以得出了,枚举sum(A序列的总和)的因数ans,然后进行check(ans),若可行则更新最终答案。

而难点在于如何去配平上面的等式,并且使得所有大于等于0的xi之和小于等于k

拿样例#2来看,当我们check(7)时:

\(10+x1=7*z1\)

\(1+x2=7*z2\)

\(2+x3=7*z3\)

\(22+x4=7*z4\)

很容易想到x的构造方案,\(x=-(xmod7)\)或\(x=7-xmod7\),正确性和最优性一目了然可以联系题目理解下:
\[
\left\{
\begin{array}{c}
x1=-3或+4……①\ x2=-1或+6……②\ x3=-2或+5……③\ x4=-1或+6……④\ \end{array}
\right.
\]
那现在面临的问题就是,对于每个xi,要么取左边的,要么取右边的,使得最后x的总和为0,且所有x的绝对值的总和/2要小于等于k

下面有一个这类问题的贪心方案:

将xi根据前一列的大小排序——忽略正负号先,得出:1 1 2 3

接着枚举中轴,然后只要当左右的和相等且均小于等于k时,则ans可行。

正确性显然,看代码感性理解下8。

#include<bits/stdc++.h>
using namespace std;
#define int long long
int sum=0;
int a[510],ans,n,k;
int sum1[510],sum2[510],p[510];
bool check(int x){
    int cnt=0;
    for(int i=1;i<=n;i++)p[i]=a[i]%x;
    sort(p+1,p+n+1);
    for(int i=1;i<=n;i++)sum1[i]=sum1[i-1]+p[i];
    for(int i=n;i>=1;i--)sum2[i]=sum2[i+1]+x-p[i];
    int mi=k;
    for(int i=1;i<=n;i++){
        if(sum1[i]==sum2[i+1]){
            if(sum1[i]<=k)return 1;
            else return 0;
        }
    }
    return 0;
}
signed main(){
    scanf("%lld%lld",&n,&k);
    for(int i=1;i<=n;i++)scanf("%lld",&a[i]),sum+=a[i];
    for(int i=1;i*i<=sum;i++)if(sum%i==0){
        if(check(i))ans=max(ans,i);
        if(check(sum/i))ans=max(ans,sum/i);
    }
    cout<<ans;
}

F - Enclosed Points

题目描述:

给定n个点,用坐标\((xi,yi)\)表示,设这n个点构成集合S,求对于任意S的非空子集T的\(f(T)\)总和。

对于函数\(f(T)\)的定义如下:设T包含的点中,x值最小的为\(Xmin\),x最大的为\(Xmax\),y值最小的为\(Ymin\),y最大的为\(Ymax\)。则该函数的值为:满足\(Xmin<=x<=Xmax且Ymin<=y<=Ymax\)的点(x,y)的个数。

数据范围&输入输出格式
  • \(1≤N≤2×10^5\)
  • \(?10^9≤xi,yi≤10^9\)
  • \(xi≠xj(i≠j)\),\(yi≠yj(i≠j)\)
  • All values in input are integers.
样例:

输入样例#1

3
-1 3
2 1
3 -2

输出样例#1

13

样例#1解释

输入样例#2

10
19 -11
-3 -12
5 3
3 -15
8 -14
-9 -20
10 -9
0 2
-7 17
6 -6

输出样例#2

7222
题解:

找到正确的思考角度就比较好做了。

思路step 1:独立每个点对答案的贡献。

思路step 2:求每个点不被哪些集合包含,最后将总方案数减一下。(当然如果正着做也可以,反着会比较简单)

前置知识:对于一个含n个点的集合,它的非空子集数为\(2^n-1\)

所有在这道题里。

注意题面,保证了\(xi≠xj,yi≠yj\)。

先将坐标离散一下,然后将每个点按照x坐标排序。

图中黄点表示当前遍历到的点\(x\)。

区域一,区域二中分别含有的点的个数用\(s[x][1]\),\(s[x][2]\)表示,可以在\(O(nlogn)\)的时间内用树状数组维护得到。区域三,区域四中点的个数也是一样的统计方法,倒着扫一遍即可。

现在我们得出了每个区域含有点的个数。对于\(x\)这个点而言,我们现在的问题是统计:不含有x的集合的个数

很明显就是将图中四个绿色的区域的方案总数减去图中四个紫色区域的方案总数。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e5+10,mod=998244353;
int a[N],b[N],c[N],ans;
int s[N][3],two[N],n;
struct node{
    int x,y;
}p[N];
inline bool cmp(node p,node q){return p.x<q.x;}
void add(int x){while(x<=n)c[x]++,x+=x&(-x);}
int sum(int x){
    int res=0;
    while(x){
        res+=c[x];
        x-=x&(-x);
    }
    return res;
}
void calc(int tot,int d){
    ans=(ans+(two[tot]-1)*d%mod)%mod;
}
signed main(){
    scanf("%lld",&n);
    two[0]=1;
    for(int i=1;i<=n;i++)two[i]=two[i-1]*2%mod;
    for(int i=1;i<=n;i++){
        scanf("%lld%lld",&p[i].x,&p[i].y);
        a[i]=p[i].x;
        b[i]=p[i].y;
    }
    sort(a+1,a+n+1);sort(b+1,b+n+1);
    sort(p+1,p+n+1,cmp);
    for(int i=1;i<=n;i++){
        p[i].x=lower_bound(a+1,a+n+1,p[i].x)-a;
        p[i].y=lower_bound(b+1,b+n+1,p[i].y)-b;
    }
    for(int i=1;i<=n;i++){
        int y=p[i].y;
        s[i][2]=sum(y-1),s[i][1]=i-s[i][2]-1;
        add(y);
    }
    memset(c,0,sizeof(c));
    for(int i=n;i>=1;i--){
        int y=p[i].y;
        int s4=sum(y-1),s3=n-i-s4;
        int tmp=ans;
        calc(s[i][1]+s3,1);
        calc(s[i][1]+s[i][2],1);
        calc(s[i][2]+s4,1);
        calc(s3+s4,1);
        calc(s[i][1],-1);
        calc(s[i][2],-1);
        calc(s3,-1);
        calc(s4,-1);
        add(y);
    }
    printf("%lld",(n*(two[n]-1)%mod-ans+mod)%mod);
}

原文地址:https://www.cnblogs.com/Tieechal/p/11303995.html

时间: 2024-11-08 00:40:40

AtCoder Beginner Contest 136的相关文章

AtCoder Beginner Contest 103 D(贪心)

AtCoder Beginner Contest 103 D 题目大意:n个点,除第n个点外第i与第i+1个点有一条边,给定m个a[i],b[i],求最少去掉几条边能使所有a[i],b[i]不相连. 按右端点从小到大排序,如果当前选的去掉的边在区间内,那么符合条件,否则ans++,并贪心地把去掉的边指向右端点,因为前面的区间都满足条件了,所以要去掉的边要尽量向右移使其满足更多的区间. 1 #include <iostream> 2 #include <cstdio> 3 #incl

AtCoder Beginner Contest 154 题解

人生第一场 AtCoder,纪念一下 话说年后的 AtCoder 比赛怎么这么少啊(大雾 AtCoder Beginner Contest 154 题解 A - Remaining Balls We have A balls with the string S written on each of them and B balls with the string T written on each of them. From these balls, Takahashi chooses one

AtCoder Beginner Contest 155 简要题解

AtCoder Beginner Contest 155 A:签到失败,WA一次. int main() { int a, b, c; cin >> a >> b >> c; if(a == b && b == c) cout << "No"; else if(a == b || a == c || b == c) cout << "Yes"; else cout << &quo

AtCoder Beginner Contest 152 - F - Tree and Constraints (容斥定理+树上路径的性质)

AtCoder Beginner Contest 152 - F - Tree and Constraints (容斥定理+树上路径的性质) We have a tree with NN vertices numbered 11 to NN. The ii-th edge in this tree connects Vertex aiai and Vertex bibi. Consider painting each of these edges white or black. There ar

【ATcoder】AtCoder Beginner Contest 161 题解

题目链接:AtCoder Beginner Contest 161 原版题解链接:传送门 A - ABC Swap 这题太水,直接模拟即可. 1 #include <iostream> 2 using namespace std; 3 int main() { 4 int a, b, c; 5 cin >> a >> b >> c; 6 swap(a, b); 7 swap(a, c); 8 cout << a << " &

AtCoder Beginner Contest 115 题解

题目链接:https://abc115.contest.atcoder.jp/ A Christmas Eve Eve Eve 题目: Time limit : 2sec / Memory limit : 1024MB Score : 100 points Problem Statement In some other world, today is December D-th. Write a program that prints Christmas if D=25, Christmas E

AtCoder Beginner Contest 106 ABCD

A - Garden Problem Statement There is a farm whose length and width are A yard and B yard, respectively. A farmer, John, made a vertical road and a horizontal road inside the farm from one border to another, as shown below: (The gray part represents

AtCoder Beginner Contest 121 题解

题目链接:https://atcoder.jp/contests/abc121 A White Cells 分析:题目数据规模很小,直接暴力修改都可以.或者可以推出公式. 代码: 1 #include <iostream> 2 #include <cstdio> 3 4 using namespace std; 5 6 int main() 7 { 8 int a[25][25] = {0}; 9 int H, W, h, w; 10 scanf("%d %d"

AtCoder Beginner Contest 132 F - Small Products

数 sqrt 缩小范围 整除分块 1 #include <cstdio> 2 #include <cstdlib> 3 #include <cmath> 4 #include <cstring> 5 #include <string> 6 #include <algorithm> 7 #include <iostream> 8 using namespace std; 9 #define ll long long 10 1