Codeforces Round #547 (Div. 3)全部题解

A. Game 23

如果m可以整除n,那么判断m/n是否只由2和3相乘得到。

#include "bits/stdc++.h"
using namespace std;
int main() {
    int n,m;
    cin>>n>>m;
    int a=m/n;
    if(a*n!=m){
        printf("-1\n");
        return 0;
    }
    int a2=0,a3=0;
    while(a%2==0){
        a2++;
        a/=2;
    }
    while(a%3==0){
        a3++;
        a/=3;
    }
    if(a!=1)
    {
        printf("-1\n");
        return 0;
    }
    printf("%d\n",a2+a3);
}

B. Maximal Continuous Rest

直接找最长连续,特判首尾即可。

#include "bits/stdc++.h"
using namespace std;
int a[200004];
int main() {
    int n;
    cin>>n;
    for (int i = 1; i <= n; ++i) {
        cin>>a[i];
    }
    int ans=0;
    int len=0;
    for (int i = 1; i <= n; ++i) {
        if(a[i]==1)len++;
        else
        {
            ans=max(ans,len);
            len=0;
        }
    }
    int len1=0,len2=0;
    for (int i = 1; i <= n; ++i) {
        if(a[i]==1)len1++;
        else break;
    }
    for (int i = n; i >= 1; --i) {
        if(a[i]==1)len2++;
        else break;
    }
    ans=max(ans,min(len1+len2,n));
    printf("%d\n",ans);
}

C. Polycarp Restores Permutation

将差分数组还原,第一个值的取值可以决定整体,那么还原后排序,判断是否满足条件,最后加上差值。

#include "bits/stdc++.h"
using namespace std;
int a[200004];
int b[200004];
int c[200004];
int main() {
    int n;
    cin>>n;
    for (int i = 1; i <= n-1; ++i) {
        cin>>a[i];
    }
    b[1]=0;
    c[1]=0;
    for (int i = 2; i <= n; ++i) {
        b[i]=b[i-1]+a[i-1];
        c[i]=b[i];
    }
    sort(c+1,c+n+1);
    int ok=1;
    for (int i = 2; i <= n; ++i) {
        if(i-c[i]!=i-1-c[i-1]){
            ok=0;
            break;
        }
    }
    if(ok)
    {
        int d=1-c[1];
        for (int i = 1; i <= n; ++i) {
            printf("%d ",b[i]+d);
        }
        puts("");
    }
    else puts("-1");
}

D. Colored Boots

瞎JB模拟,没啥好说的。

#include "bits/stdc++.h"
using namespace std;
vector<pair<int,int>>ans;
bool vis[1500004];
int main() {
    int n;
    cin>>n;
    string s1,s2;
    cin>>s1>>s2;
    memset(vis,0, sizeof(vis));
    unordered_map<char,vector<int>>mp;
    for (int i = 0; i < n; ++i) {
        mp[s1[i]].push_back(i);
    }
    vector<int>v;
    for (int i = 0; i < n; ++i) {
        if(s2[i]!='?'&&mp[s2[i]].size())
        {
            ans.push_back({i,mp[s2[i]][0]});
            vis[mp[s2[i]][0]]=1;
            mp[s2[i]].erase( mp[s2[i]].begin());
        }
        else if((s2[i]!='?'&&mp['?'].size()))
        {
            ans.push_back({i,mp['?'][0]});
            vis[mp['?'][0]]=1;
            mp['?'].erase(mp['?'].begin());
        }
        else if(s2[i]=='?')v.push_back(i);
    }
    int cnt=0;
    for (int i = 0; i < n&&cnt<v.size(); ++i) {
        if(!vis[i])
        {
            ans.push_back({v[cnt++],i});
        }
    }
    printf("%d\n",ans.size());
    for (int i = 0; i < ans.size(); ++i) {
        printf("%d %d\n",ans[i].second+1,ans[i].first+1);
    }
}

E. Superhero Battle

循环,没啥可讲的。

#include "bits/stdc++.h"
using namespace std;
long long a[200004];
int main() {
    long long h,n;
    cin>>h>>n;
    for (int i = 0; i < n; ++i) {
        cin>>a[i];
    }
    long long pre=0,base=8e18;
    for (int i = 0; i < n; ++i) {
        pre+=a[i];
        base=min(base,pre);
    }
    long long left=h+base;
    if(left<=0)
    {
        long long ans=0;
        for (int i = 0; i < n; ++i) {
            h+=a[i];
            ans++;
            if(h<=0)break;
        }
        printf("%lld\n",ans);
    }
    else
    {
        if(pre>=0)printf("-1\n");
        else
        {
            long long ans=0;
            ans+=n*(left/(-pre));
            h-=(left/(-pre))*(-pre);
            while(h>0)
                for (int i = 0; i < n; ++i) {
                    h+=a[i];
                    ans++;
                    if(h<=0)break;
                }
            printf("%lld\n",ans);
        }
    }
}

F1. Same Sum Blocks (Easy) && F2. Same Sum Blocks (Hard)

因为只能找连续的区间,所以能得到的区间个数只有n*(n+1)个。

最多只有2250000个区间,预处理前缀和,把所有区间的信息求出来:左右端点,sum

按sum值分类,然后问题就变成了:若干个区间,不能重叠,最多能安置几个区间。

将区间按照左端点排序,记录一个已覆盖区间的右端点值R,每当一个新区间要加进来时:

如果l>R,那么将该区间加入

如果r<R,那么该区间可以代替上一个区间

之后乱搞就完事儿了。

#include "bits/stdc++.h"
using namespace std;
int a[1504];
int pre[1504];
struct node
{
    int l,r,w;
    bool friend operator < (node &a,node &b)
    {
        return a.w<b.w;
    }
}b[2250004];
bool cmp(node &a,node &b)
{
    if(a.l==b.l)return a.r<b.r;
    else return a.l<b.l;
}
int main() {
    int n;
    cin>>n;
    pre[0]=0;
    for (int i = 1; i <= n; ++i) {
        cin>>a[i];
        pre[i]=pre[i-1]+a[i];
    }
    int cnt=0;
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= i; ++j) {
            b[cnt++]={j,i,pre[i]-pre[j-1]};
        }
    }
    sort(b,b+cnt);
    int l=0,r=0;
    int ans=0;
    vector<pair<int,int>>v;
    vector<pair<int,int>>anss;
    for (l = 0; l < cnt; l=r) {
        for (r = l; r < cnt; ++r) {
            if(b[r].w!=b[l].w)break;
        }
        sort(b+l,b+r,cmp);
        int sum=0;
        int R=0;
        v.clear();
        for (int i = l; i < r; ++i) {
            if(b[i].l>R){
                sum++;
                R=b[i].r;
                v.push_back({b[i].l,b[i].r});
            }
            else if(b[i].r<R)
            {
                R=b[i].r;
                v.erase(v.end()-1);
                v.push_back({b[i].l,b[i].r});
            }
        }
        if(sum>ans)
        {
            ans=sum;
            anss=v;
        }
    }
    printf("%d\n",ans);
    for (int i = 0; i < anss.size(); ++i) {
        printf("%d %d\n",anss[i].first,anss[i].second);
    }
    return 0;
}

G. Privatization of Roads in Treeland

有K个城市可以有多个公司,那么预处理每个点的度,按照从大到小的顺序找出K个城市,此时就满足最优。

然后跑一个dfs,当跑到被安排的城市时,其连接的边全部赋值为1,当跑到没有被安排的城市时,依次给边赋值,注意不能与上一个城市所操作的边有重复的值,所以这里记录一个前缀prec即可。

这里我直接对point结构体排序T了,估计是因为vector的锅。把里面的v.size和u单独提出来操作,就只跑了200+ms。

#include "bits/stdc++.h"
using namespace std;
struct node
{
    int u,id;
};
struct point
{
    vector<node>v;
    int u;
}a[200004];
struct xxx
{
    int num,u;
}b[200004];
bool isok[200004];
int line[200004];
bool cmp(xxx a,xxx b)
{
    return a.num>b.num;
}
void dfs(int u,int pre,int prec)
{
    //if(u==pre)return;
    int cnt=1;
    if(isok[u])
        for (int i = 0; i < a[u].v.size(); ++i) {
            if(a[u].v[i].u==pre)continue;
            line[a[u].v[i].id]=1;
            dfs(a[u].v[i].u,u,1);
        }
    else
        for (int i = 0; i < a[u].v.size(); ++i) {
            if(a[u].v[i].u==pre)continue;
            if(cnt==prec)cnt++;
            line[a[u].v[i].id]=cnt;
            dfs(a[u].v[i].u,u,cnt);
            cnt++;
        }
}
int main() {
    int n,k;
    cin>>n>>k;
    for (int i = 0; i < n-1; ++i) {
        int x,y;
        scanf("%d%d",&x,&y);
        a[x].v.push_back({y,i+1});
        a[y].v.push_back({x,i+1});
    }
    memset(isok,false, sizeof(isok));
    for (int i = 1; i <= n; ++i) {
        b[i].u=i;
        b[i].num=a[i].v.size();
    }
    sort(b+1,b+n+1,cmp);
    for (int i = 1; i <= k; ++i) {
        isok[b[i].u]=1;
    }
    int ans=b[k+1].num;
    dfs(1,-1,-1);
    printf("%d\n",ans);
    for (int i = 1; i <= n-1; ++i) {
        printf("%d ",line[i]);
    }
    puts("");
    return 0;
}

感觉这场打了的话可以拿一个不错的rk,可惜啊(;´д`)ゞ打比赛是不可能打比赛的,只有补题才能勉强维持生活

猜你喜欢

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