Codeforces Round #822 (Div. 2) 题解

A. Select Three Sticks

题意为每一次可以选一个数加1或减1,问达到数组中有三个相等的数的最小步数

签到题,可能会有很多种解法

这里说其中一种

我们把整个数组排序,然后对于每一个三元组,把紧邻他的前后元素改成此元素,更新答案即可

代码如下

#include <bits/stdc++.h>
#define int long long
#define pb push_back
#define fer(i,a,b) for(int i=a;i<=b;++i)
#define der(i,a,b) for(int i=a;i>=b;--i)
#define all(x) (x).begin(),(x).end()
#define pll pair<int,int>
#define et  cout<<'\n'
#define x first
#define y second
using namespace std;
template <typename _Tp>void input(_Tp &x){
    char ch(getchar());bool f(false);while(!isdigit(ch))f|=ch==45,ch=getchar();
    x=ch&15,ch=getchar();while(isdigit(ch))x=x*10+(ch&15),ch=getchar();
    if(f)x=-x;
}
template <typename _Tp,typename... Args>void input(_Tp &t,Args &...args){input(t);input(args...);}
const int N=1e6+10;
int a[N];
signed main(){
    int T;
    cin>>T;
    while(T--){
        int n;
        cin>>n;
        fer(i,1,n){
            fer(j,1,i){
                if(j==1 || j==i){
                    cout<<1<<" ";
                }
                else{
                    cout<<0<<" ";
                }
            }
            cout<<'\n';
        }
    }
	
}

 B. Bright, Nice, Brilliant 

这个题意真的是晦涩难懂

意思就是,每个房间\large a_{i,j}可以通向\large a_{i+1,j}\large a_{i+1,j+1}

每个房间的亮度等于 他自己的是否亮+与多少个亮的房间可以到达他

就比如这个图吧,我们拿\large a_{4,3}举例,因为他自带一个亮度,而可以到达他并且亮的房间是

\large a_{1,1}+a_{2,1}+a_{3,2},所以他的亮度是4

而题意让我们输出一个,每一层所有房间亮度都相等的金字塔

其实第三个样例已经提示答案了,我们只需要让两边是亮的即可,大家看这张图

 假设我们验证一下最底层的11-15号点,对于11号点,他的亮度为5(1,2,4,7,11)

而每向右移动一格,左边会减少一个亮度(11),右边就会增加一个亮度(3)

每一格都是这样,也就保证了每一层所有格子亮度相同

 代码如下

const int N=1e6+10;
int a[N];
signed main(){
    int T;
    cin>>T;
    while(T--){
        int n;
        cin>>n;
        fer(i,1,n){
            cin>>a[i];
        }
        sort(a+1,a+1+n);
        int res=1e9+7;
        fer(i,2,n-1){
            res=min(res,abs(a[i]-a[i-1])+abs(a[i+1]-a[i]));
        }
        cout<<res<<'\n';
    }
	
}

C. Removing Smallest Multiples

题意大概意思是,给我们一个要删的集合,1e6以内

选一个数K,你可以删掉集合中最小K的倍数,花费为K

首先我们知道暴力是一定不可以的,因为判断每一个数最差都要On,n方就爆了

我们可以换一个思路来枚举K,之后枚举K的倍数(这个过程是logn)

如果命中,就把K用掉

整体复杂度是n*logn,可以过

代码如下

#include <bits/stdc++.h>
#define int long long
#define pb push_back
#define fer(i,a,b) for(int i=a;i<=b;++i)
#define der(i,a,b) for(int i=a;i>=b;--i)
#define all(x) (x).begin(),(x).end()
#define pll pair<int,int>
#define et  cout<<'\n'
#define x first
#define y second
using namespace std;
template <typename _Tp>void input(_Tp &x){
    char ch(getchar());bool f(false);while(!isdigit(ch))f|=ch==45,ch=getchar();
    x=ch&15,ch=getchar();while(isdigit(ch))x=x*10+(ch&15),ch=getchar();
    if(f)x=-x;
}
template <typename _Tp,typename... Args>void input(_Tp &t,Args &...args){input(t);input(args...);}
const int N=1e6+10;
int a[N];
int st[N];
string s;
int n;
signed main(){
    int T;
    input(T);
    while(T--){
        input(n);
        cin>>s;
        s='0'+s;
        fer(i,0,n) st[i]=0;
        int res=0;
        fer(i,1,n){
            for(int j=i;j<=n;j+=i){
                if(s[j]=='1') break;
                if(st[j]){
                    continue;
                }
                if(s[j]=='0' && !st[j]){
                    res=res+i;
                    st[j]=1;
                }
            }
        }
        printf("%lld\n",res);
 
    }
	
}

D. Slime Escape

题意大概为,给一个数组a,现在在k位置,可以左右吃但不能吃成负数,问可不可以走到0或n+1,也就是走出这个数组的一边

这道题一样非常多的解法,有一边扩张另一边队列的,有双指针两边扩张的等等

但无一例外就是 难写!

大家可以去翻一下cf的榜,找一个自己好理解的写法

这里介绍一种写法

大致思路就是先向一边走,把另一边用队列存起来

如果走不通了,就用走过去经过的最大值向另一边扩张

再用另一边的最大值向原方向扩张

之后两个方向进行两次

需要记录沿途吸收的能力,目前能量

这题是真的恶习

#include <bits/stdc++.h>
#define int long long
#define pb push_back
#define fer(i,a,b) for(int i=a;i<=b;++i)
#define der(i,a,b) for(int i=a;i>=b;--i)
#define all(x) (x).begin(),(x).end()
#define pll pair<int,int>
#define et  cout<<'\n'
#define x first
#define y second
using namespace std;
template <typename _Tp>void input(_Tp &x){
    char ch(getchar());bool f(false);while(!isdigit(ch))f|=ch==45,ch=getchar();
    x=ch&15,ch=getchar();while(isdigit(ch))x=x*10+(ch&15),ch=getchar();
    if(f)x=-x;
}
template <typename _Tp,typename... Args>void input(_Tp &t,Args &...args){input(t);input(args...);}
const int N=1e6+10;
int a[N];
int n,k;
int qz[N];
bool check(int t){
    fer(i,1,n){
        qz[i]=qz[i-1]+a[i];
    }
    queue<int> q;
    der(i,t-1,1){
        q.push(a[i]);
    }
    int now=a[t];
    int v=now;
    int id=t;
    fer(i,t+1,n){
        if(now+a[i]>=0){
            now+=a[i];
            if(now-v>=0){
                v=now;
                id=i;
            }
        }
        else{
            while(q.size()!=0){
                if(q.size()&&q.size()==1){
                    auto t=q.front();
                    if(v+t>=0) return true;
                }
                int t=q.front();
                if(v+t>=0){
                    v+=t;
                    now+=t;
                    q.pop();
                    if(v+qz[i]-qz[id]>=0){
                        now+=a[i];
                        if(now>=v){
                            id=i;
                            v=now;
                        }
                        break;
                    }
                }
                else{
                    return false;
                }
            }
        }
    }
    return true;
}
signed main(){
    int T;
    input(T);
    fer(kk,1,T){
        input(n,k);
        fer(i,1,n){
            input(a[i]);
        }
        bool fl=0;
        if(check(k)){
            fl=1;
        }
        reverse(a+1,a+1+n);
        if(check(n-k+1)){
            fl=1;
        }
        if(fl==1){
            cout<<"YES"<<'\n';
        }
        else{
            cout<<"NO"<<'\n';
        }
    }
	
}

E. Rectangular Congruence

题意:要求构造一个n*n的矩阵,满足以下条件

\large a_{i,i}=b_{i}

\large a_{r1,c1}+a_{r2,c2}!=a_{r1,c2}+a_{r2,c1} %n

保证n为素数

这是个半结论题

我们把第二个条件移项

\large a_{r1,c1}-a_{r1,c2}!=a_{r2,c1}-a_{r2,c2}mod n

因此我们只需要让每一行为公差不同的等差数列即可 公差在0-n-1

而结合第一个条件,我们要让

\large a_{i,j}=(i*(j-i+n)+b_{i})

即可

代码如下:

#include <bits/stdc++.h>
#define int long long
#define pb push_back
#define fer(i,a,b) for(int i=a;i<=b;++i)
#define der(i,a,b) for(int i=a;i>=b;--i)
#define all(x) (x).begin(),(x).end()
#define pll pair<int,int>
#define et  cout<<'\n'
#define x first
#define y second
using namespace std;
template <typename _Tp>void input(_Tp &x){
    char ch(getchar());bool f(false);while(!isdigit(ch))f|=ch==45,ch=getchar();
    x=ch&15,ch=getchar();while(isdigit(ch))x=x*10+(ch&15),ch=getchar();
    if(f)x=-x;
}
template <typename _Tp,typename... Args>void input(_Tp &t,Args &...args){input(t);input(args...);}
const int N=1e6+10;

signed main(){
    int n;
    cin >> n;
    for (int i = 0; i < n; i++) {
        int b;
        cin >> b;
        for (int j = 0; j < n; j++) {
        cout << (i * (j - i + n) + b) % n << " ";
        }
        cout << "\n";
    }
}

 这场感觉总体体验真的不是很好,,尤其是那个D

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值