Codeforces Round #587 (Div. 3)简要题解

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_42671946/article/details/101159444

A - Prefixes

分析:模拟一下就可以了。

#include "bits/stdc++.h"
using namespace std;
int main(){
    int n;
    string s;
    cin>>n>>s;
    int ans = 0;
    for (int i = 0; i < n; ++i) {
        if(i&1){
            if(s[i]==s[i-1]){
                ans ++;
                s[i]= ((s[i]-'a')^1)+'a';
            }
        }
    }
    cout<<ans<<endl<<s<<endl;
}

B - Shooting

分析:从大到小排序然后输出就可以了。证明略。

#include "bits/stdc++.h"
using namespace std;
int a[1004];
pair<int,int>p[1004];
int main(){
    int n;
    cin>>n;
    for (int i = 1; i <= n; ++i) {
        scanf("%d",&a[i]);
        p[i]=make_pair(a[i],i);
    }
    sort(p+1,p+1+n);
    int sum = 0;
    for (int i = n; i >= 1; --i) {
        sum += (n-i)*p[i].first+1;
    }
    cout<<sum<<endl;
    for (int i = n; i >= 1; --i) {
        printf("%d ",p[i].second);
    }
}

C - White Sheet

分析:找到最大的然后把其余的补到这么多就可以了。证明略。

#include "bits/stdc++.h"
using namespace std;
int a[200004];
int main(){
    int n;
    cin>>n;
    int maxi = 0;
    for (int i = 1; i <= n; ++i) {
        scanf("%d",&a[i]);
        maxi = max(maxi,a[i]);
    }
    long long sum = 0;
    int g = 0;
    for (int i = 1; i <= n; ++i) {
        sum += maxi - a[i];
        if(a[i]!=maxi){
            if(g == 0)g = maxi-a[i];
            else g = __gcd(g,maxi-a[i]);
        }
    }
    cout<<sum/g<<' '<<g<<endl;

}

D - Swords

分析:把矩形的坐标离散化一下,对于两个黑色矩形的块坐标,全部赋值为1,然后找白色的矩形上有没有不是1的就可以了。

#include "bits/stdc++.h"
using namespace std;
int x[10],y[10];
int mp[20][20];
int main(){
    vector<int>vx,vy;
    for (int i = 1; i <= 6; ++i) {
        cin>>x[i]>>y[i];
        vx.push_back(x[i]);
        vy.push_back(y[i]);
    }
    sort(vx.begin(),vx.end());
    sort(vy.begin(),vy.end());
    vx.erase(unique(vx.begin(),vx.end()),vx.end());
    vy.erase(unique(vy.begin(),vy.end()),vy.end());
    for (int i = 1; i <= 6; ++i) {
        x[i]=lower_bound(vx.begin(),vx.end(),x[i])-vx.begin()+1;
        y[i]=lower_bound(vy.begin(),vy.end(),y[i])-vy.begin()+1;
    }
    for (int i = min(x[3]+1,x[4]+1); i <= max(x[3],x[4]); ++i) {
        for (int j = min(y[3]+1,y[4]+1); j <= max(y[3],y[4]); ++j) {
            mp[i][j]=1;
        }
    }
    for (int i = min(x[5]+1,x[6]+1); i <= max(x[5],x[6]); ++i) {
        for (int j = min(y[5]+1,y[6]+1); j <= max(y[5],y[6]); ++j) {
            mp[i][j]=1;
        }
    }
    bool ok = 0;
    for (int i = min(x[1]+1,x[2]+1); i <= max(x[1],x[2]); ++i) {
        for (int j = min(y[1]+1,y[2]+1); j <= max(y[1],y[2]); ++j) {
            if(mp[i][j]!=1)ok=1;
        }
    }
    if(ok)puts("YES");
    else puts("NO");
}

E1 - Numerical Sequence (easy version)&&E2 - Numerical Sequence (hard version)

分析:E1的话可以直接暴力预处理一个前缀和,然后在前缀和里面二分找一下位置就可以了。

E2范围扩大到1e18,显然不能打前缀和的表。

对于一个数x,如果我们能找到以x结尾且x是第一次出现的位置下标(x结尾的数的下标),那么其实这个问题就比较容易去解决了,我们把这个东西称为F(n)。即F(1)=1 F(2)=3 F(3)=6

考虑一下这个序列:

1 12 123 1234 12345 123456 123456789

10 1011 101112 10111213

显然对于F(n)来说,是一个分段的等差数列,当数的位数为d时,公差为d,那么很容易,我们就可以在log的时间内求出F(n)。

扫描二维码关注公众号,回复: 7657700 查看本文章

显然F(n)是单调的,那么我们可以二分一下找出F(n)<=k的n的最大值,那么此时从F(n)+1位置开始的序列,是像这样的:

123456789101112……

即从这个序列中找到第k-F(n)个数(注意k==F(n)时应该取前一个),这个也可以看成一个分段的等差数列(d=0),然后这题就做完了。

#include<bits/stdc++.h>
const double eps = 1e-4;
using namespace std;

long long getdig(long long n) {
    long long res = 0;
    while (n) {
        res++;
        n /= 10;
    }
    return res;
}

long long getans(long long k) {
    long long a = 1, base = 1;
    long long res = 0;
    long long dig = getdig(k);
    for (int i = 1; i < dig; ++i) {
        long long num = (long long)(pow(10,i-1)+eps) * 9;
        long long sum = (2 * a + (num - 1) * i) * num / 2;
        res += sum;

        a = a + num * i+1;
    }
    long long num = k - (long long)(pow(10,dig-1)+eps) + 1;
    res += (2*a+(num-1)*dig)*num/2;
    //res+=pre;
    return res;
}
string tos(long long n){
    string s,t;
    while(n){
        t+=n%10+'0';
        n/=10;
    }
    for (int i = t.length()-1; i >=0 ; --i) {
        s+=t[i];
    }
    return s;
}
void ac(long long n,long long k){
    for (int i = 1; i < 18; ++i) {
        long long num = 1LL*(long long)(pow(10,i-1)+eps)*9*i;
        if(k>num){
            k-=num;
        }
        else {
            long long x = (k+i-1)/i;
            long long y = k%i;
            if(y == 0) y = i;
            long long t = (long long)(pow(10,i-1)+eps) + x - 1;
            string s = tos(t);
            putchar(s[y-1]);
            puts("");
            break;
        }
    }
}
int main() {
    int q;
    getans(1);
    cin >> q;
    while (q--) {
        long long k;
        cin >> k;
        long long l = 1,r = 1e9;
        long long ans = -1;
        while(l<=r){
            int mid = l+r >>1;
            long long temp = getans(mid);
            if(temp<=k){
                ans = mid;
                l=mid+1;
            }
            else r = mid - 1;
        }
        k-=getans(ans);
        if(k==0){
            putchar(ans%10+'0');
            puts("");
        }
        else {
            ac(ans+1,k);
        }

    }
}

F - Wi-Fi

分析:显而易见的是一道动态规划。

每个点分为两种状态,不开路由器,开路由器。

用dp[i][0]表示第i个位置不开路由器,且让前i个全部连接到网络的最小花费;

用dp[i][1]表示第i个位置开路由器,且让前i个全部连接到网络的最小花费。

那么容易得到转移方程:

dp[i][0]=min(dp[i-1][0]+i,dp[i-k][1],dp[i-k+1][1]……dp[i-1][1])

dp[i][1]=min(dp[i-k+1][0]……dp[i-1][0],dp[i-k+1][1]……dp[i-1][1])+i

然后找个数据结构维护一下就可以了。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 15;

char x[maxn];
long long dp[maxn][2];
int main() {
    int n, k;
    deque<pair<long long,long long>>q0,q1,q2;
    cin >> n >> k;
    cin >> x + 1;
    dp[0][0] = 0;
    dp[0][1]=1e9;
    q0.push_back(make_pair(0,0));
    q1.push_back(make_pair(1e18,0));
    q2.push_back(make_pair(1e18,0));
    for(int i = 1; i <= n; i++) {
        dp[i][0]=1e18;
        dp[i][1]=1e18;
        dp[i][0] = min(dp[i][0], dp[i - 1][0] + i);
        while(q0.size() && q0.front().second<i-k-1)q0.pop_front();
        while(q1.size() && q1.front().second<i-k-1)q1.pop_front();
        while(q2.size() && q2.front().second<i-k)q2.pop_front();
        dp[i][0]=min(dp[i][0],q2.front().first);
        if(x[i] == '1') {
            dp[i][1]=min(dp[i][1],q0.front().first+i);
            dp[i][1]=min(dp[i][1],q1.front().first+i);
        }
        while(q0.size() && q0.back().first > dp[i][0])q0.pop_back();
        while(q1.size() && q1.back().first > dp[i][1])q1.pop_back();
        while(q2.size() && q2.back().first > dp[i][1])q2.pop_back();
        q0.push_back(make_pair(dp[i][0],i));
        q1.push_back(make_pair(dp[i][1],i));
        q2.push_back(make_pair(dp[i][1],i));
    }
    cout << min(dp[n][1], dp[n][0]) << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42671946/article/details/101159444