【Codeforces Round #547 (Div. 3) 】 A.B.C.D.E.F1.F2.G

前言

biubiu-biu r a t i n g + = 162 rating+=162 rating+=162 1500->1662


A. Game 23

题意

给你两个数 n n n, m m m,每次可以把 n n n 2 2 2或者乘 3 3 3,问多少次操作之后 n n n可以变成 m m m。不能输出 − 1 -1 1

做法

首先判断是否整除,之后用商不断除以 2 2 2/除以 3 3 3最后判结果是否为 1 1 1就可以。

代码

#include<stdio.h>
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    if(m%n!=0||m<n)
    {
        printf("-1");
        return 0;
    }
    int tmp=m/n;
    int cnt=0;
    while(tmp%2==0)
    {
        tmp/=2;
        cnt++;
    }
    while(tmp%3==0)
    {
        tmp/=3;
        cnt++;
    }
    if(tmp!=1) printf("-1\n");
    else  printf("%d\n",cnt);
    return 0;
}


B. Maximal Continuous Rest

题意

给你一个长度为 n n n 01 01 01串构成的环,问环上最长的连续的 1 1 1是多长,

做法

按题意模拟即可。

代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 2e5+5;
int a[maxn];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        if(a[i]==1)
        {
            int cnt=0;
            while(i<=n&&a[i]==1)
            {
                i++;
                cnt++;
            }
            ans=max(ans,cnt);
            i--;
        }
    }
    int tmp=0;
    for(int i=1;i<=n;i++)
    {
        if(a[i]==1) tmp++;
        else break;
    }
    for(int i=n;i>=1;i--)
    {
        if(a[i]==1) tmp++;
        else break;
    }
    ans=max(ans,tmp);
    printf("%d\n",ans);
    return 0;
}



C. Polycarp Restores Permutation

题意

给你一个长度为 n n n的数组差分后的数组(差分数组长度为 n − 1 n-1 n1)。
问原数组是否是一个 1 − n 1-n 1n的排列。

做法

首先我们可以知道如果固定数组中的第一个数,就能还原数组,而且如果原数组是 [ 1 , n ] [1,n] [1,n]排列,还原后的数组一定是 [ k , k + n − 1 ] [k ,k+n-1] [k,k+n1]的排列,所以只要判断还原后的数组是否满足情况即可。注意下标不要越界。

代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 2e5+5;
const int INF = 0x3f3f3f3f;
int a[maxn];
int vis[maxn];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n-1;i++) scanf("%d",&a[i]);
    int minn=INF,maxx=-INF;
    a[0]=0;
    for(int i=1;i<=n-1;i++)
    {
        a[i]=a[i-1]+a[i];
        minn=min(minn,a[i]);
        maxx=max(maxx,a[i]);
    }
    minn=min(minn,0);
    maxx=max(maxx,0);
    if(maxx-minn+1==n)
    {
        for(int i=0;i<=n-1;i++) a[i]=a[i]+(1-minn);
        for(int i=0;i<=n-1;i++)
        {
            if(vis[a[i]])
            {
                printf("-1\n");
                return 0;
            }
            vis[a[i]]=1;
        }
        for(int i=0;i<=n-1;i++) printf("%d ",a[i]);
    }
    else printf("-1\n");
    return 0;
}



D. Colored Boots

题意

给你两个长度为 n n n的字符串,字符集为小写字母和?。两个字符匹配的条件是要么两个字符相等,要么其中一个字符为?。问两个字符串最多有多少对字符匹配。

做法

首先如果两个字符相等而且是小写字母肯定直接匹配,不浪费?
之后两边分别用?去匹配剩下的小写字母,最后如果两端?均有剩余,再用两个?进行匹配。

代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
typedef pair <int, int> pii;
const int maxn =2e5+5;
#define Se second
#define Fi first
#define pb push_back
int sum[2][27];
char str1[maxn],str2[maxn];
vector<int> tt[2][27];
vector<pii> ansv;
int main()
{
    //ios::sync_with_stdio(false);
    //freopen("a.txt","r",stdin);
    //freopen("b.txt","w",stdout);
    int n;
    scanf("%d",&n);
    scanf("%s",str1);
    scanf("%s",str2);
    for(int i=0;i<n;i++)
    {
        if(str1[i]=='?')
        {
            tt[0][26].push_back(i+1);
            sum[0][26]++;
        }
        else
        {
            tt[0][str1[i]-'a'].pb(i+1);
            sum[0][str1[i]-'a']++;
        }
    }
     for(int i=0;i<n;i++)
    {
        if(str2[i]=='?')
        {
            tt[1][26].push_back(i+1);
            sum[1][26]++;
        }
        else
        {
            tt[1][str2[i]-'a'].pb(i+1);
            sum[1][str2[i]-'a']++;
        }
    }
    int ans=0;
    int cnt1=0,cnt2=0;
    for(int i=0;i<26;i++)
    {
        ans+=min(sum[0][i],sum[1][i]);
        int tmp=min(sum[0][i],sum[1][i]);
        int ty=min(tt[0][i].size(),tt[1][i].size());
        for(int j=tt[0][i].size()-1,k=tt[1][i].size()-1;j>=0&&k>=0;j--,k--)
        {
            ansv.push_back(pii(tt[0][i][j],tt[1][i][k]));
            tt[0][i].pop_back();
            tt[1][i].pop_back();
        }
    }
    for(int i=0;i<26;i++)
    {
        if(tt[0][i].size()>0)
        {
            int tq=tt[0][i].size()-1;
            while(sum[1][26]>0&&tq>=0)
            {
                sum[1][26]--;
                ans++;
                ansv.push_back(pii(tt[0][i][tq],tt[1][26][sum[1][26]]));
                tq--;
            }
        }
        if(tt[1][i].size()>0)
        {
            int tq=tt[1][i].size()-1;
            while(sum[0][26]>0&&tq>=0)
            {
                sum[0][26]--;
                ans++;
                ansv.push_back(pii(tt[0][26][sum[0][26]],tt[1][i][tq]));
                tq--;
            }
        }
    }
    while(sum[0][26]>0&&sum[1][26]>0)
    {
        sum[0][26]--;
        sum[1][26]--;
        ans++;
        ansv.push_back(pii(tt[0][26][sum[0][26]],tt[1][26][sum[1][26]]));
    }
    printf("%d\n",ans);
    for(int i=0;i<ans;i++) printf("%d %d\n",ansv[i].Fi,ansv[i].Se);
    return 0;
}



E. Superhero Battle

题意

有一个怪兽,初始血量为 H H H,他的血量变化情况是一个长度为 n n n轮的周期。问怪兽会在第几轮死去。

1 ≤ H ≤ 1 0 12 1 \leq H \leq 10^{12} 1H1012
1 ≤ n ≤ 2 × 1 0 5 1 \leq n \leq 2 \times 10^5 1n2×105
做法

首先如果怪兽血量在一个周期内不曾小于等于 0 0 0而且每个周期之后怪兽血量增加,直接输出 − 1 -1 1
之后要知道,怪兽在某个完整的周期之前到达x血量,怪兽就撑不过这轮。
这个 x x x的求法就是遍历一遍周期,找到某个时刻怪兽血量消耗最多。
之后就假设怪兽初始血量为 H − x H-x Hx。看怪兽能撑过几个完整的轮,设这里轮数为 k k k,每轮怪兽血量减少 s u m sum sum,则要满足
s u m × k + x ≥ H sum\times k+x\ge H sum×k+xH
k ≥ H − x s u m k\ge \frac{H-x}{sum} ksumHx
所以不等式右面要上取整得到 k k k,之后再 O ( n ) O(n) O(n)的进行一个周期看怪兽在第几轮死即可。
代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 2e5+5;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
int a[maxn];
int n;
ll H;
ll sum;
int check(ll mid)
{
    ll tt=H;
    tt+=(mid-1)*sum;
    if(tt<=0) return 0;
    for(int i=1;i<=n;i++)
    {
        tt+=a[i];
        if(tt<=0) return i;
    }
    return -1;
}
int main()
{
    scanf("%lld%d",&H,&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    sum=0;
    int flag=0;
    ll tmp=H;
    ll minn=LL_INF;
    int pos;
    for(int i=1;i<=n;i++)
    {
        sum+=a[i];
        tmp+=a[i];
        if(sum<minn)
        {
            minn=sum;
            pos=i;
        }
        if(tmp<=0)
        {
            flag=i;
            break;
        }
    }
    if(flag!=0)
    {
        printf("%d\n",flag);
        return 0;
    }
    if(sum>=0)
    {
        printf("-1");
        return 0;
    }
    minn=-minn;
    sum=-sum;
    ll ans=(H-minn)/sum+((H-minn)%sum!=0);
    H=H-ans*sum;
    if(H==0)
    {
        printf("%lld\n",ans*n);
        return 0;
    }
    for(int i=1;i<=n;i++)
    {
        H+=a[i];
        if(H<=0)
        {
            printf("%lld\n",ans*n+i);
            return 0;
        }
    }
    return 0;
}



F1.F2. Same Sum Blocks

题意

给你一个长度为n的数组,找出尽量多的不相交的区间并且他们的区间和相等。

1 ≤ n ≤ 1500 1 \leq n \leq 1500 1n1500

做法

由于 n = 1500 n=1500 n=1500,区间和只有 1500 × 1500 1500 \times 1500 1500×1500 种,所以我们这些区间和作为最终的答案,对于每种区间和可以得到很个区间,对于每种区间和的问题就转化为给你n个区间找出最多的不相交区间的问题,这个问题按照r排序之后贪心的从左到右选即可,之后对每种区间和的答案取 m a x max max,这道题就做完了。

代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<map>
#include<vector>
#include<unordered_map>
using namespace std;
typedef pair <int, int> pii;
const int maxn = 1e6+5;
#define pb push_back
#define Se second
#define Fi first
int a[maxn];
vector<pii> anss;
vector<pii>tmp;
map<int,int> r;
unordered_map<int,vector<pii>>  mp;
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++) a[i]=a[i-1]+a[i];
    int ans=1;
    anss.push_back(pii(1,1));
    vector<int> rr;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=i;j++)
        {
            int tmp=a[i]-a[j-1];
            if(r.find(tmp)==r.end()||r[tmp]<j)
            {
                mp[tmp].pb(pii(j,i));
                r[tmp]=i;
            }
        }
    }
    for(unordered_map<int,vector<pii> >::iterator it=mp.begin();it!=mp.end();++it)
    {
        if((*it).Se.size()>ans)
        {
            ans=(*it).Se.size();
            anss=(*it).Se;
        }
    }
    printf("%d\n",ans);
    for(int i=0;i<ans;i++) printf("%d %d\n",anss[i].Fi,anss[i].Se);
    return 0;
}



G. Privatization of Roads in Treeland

题意

给你一棵 n n n个结点的树,现在要对每条边染色,如果一个节点所连接的边的颜色中有相同的,则这个点是坏点,现在问如果要使坏点的个数不超过 k k k,问最少要用多少种颜色去染边。

做法

首先由于这是一颗树,也就是每两个点只会被一条边影响,所以可以认为每个点染色是独立的。因为对于每条边至少染一种颜色,所以这条边如何染色不影响另一个点,之后我们贪心的选择度数最大的 k k k个点去放弃这些点,然后从任意一点开始 d f s dfs dfs染色即可。对于不放弃的点,他与所有子节点和父节点的边颜色均不相同。对于已放弃的点,全都染同一个色即可。最后统计最多用了几种颜色。

代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
typedef pair <int, int> pii;
const int maxn = 2e5+5;
#define Fi first
#define Se second
#define pb push_back
struct data
{
    int pos;
    int ind;
}x[maxn];
vector<pii>G[maxn];
bool cmp(const data &a,const data &b)
{
    if(a.ind==b.ind) return a.pos<b.pos;
    return a.ind>b.ind;
}
int vis[maxn];
int ans[maxn];
void dfs(int rt,int fa,int col)
{
    int tmp=0;
    for(int i=0;i<G[rt].size();i++)
    {
        int to=G[rt][i].Fi;
        int id=G[rt][i].Se;
        if(to==fa) continue;
        if(vis[rt]==1)
        {
            ans[id]=1;
            dfs(to,rt,1);
        }
        else
        {
            if(++tmp==col) tmp++;
            ans[id]=tmp;
            dfs(to,rt,tmp);
        }
    }
}
int main()
{
    int n,k,u,v;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n-1;i++)
    {
        scanf("%d%d",&u,&v);
        G[u].pb(pii(v,i));
        G[v].pb(pii(u,i));
        x[u].ind++;
        x[v].ind++;
    }
    for(int i=1;i<=n;i++) x[i].pos=i;
    sort(x+1,x+1+n,cmp);
    for(int i=1;i<=k;i++) vis[x[i].pos]=1;
    dfs(1,-1,-1);
    int maxx=0;
    for(int i=1;i<=n-1;i++) maxx=max(maxx,ans[i]);
    printf("%d\n",maxx);
    for(int i=1;i<=n-1;i++) printf("%d ",ans[i]);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值