【Codeforces】Round #764 (Div. 3) 补题

A. Plus One on the Subset

题目链接

思路:数列中最大值减去最小值就可以

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int maxn=500+10;
int n;
int a[maxn];
int main()
{
    int t;cin>>t;
    while(t--)
    {
        cin>>n;
        for(int i=1;i<=n;i++)
            cin>>a[i];
        int maxx=a[1],minn=a[1];
        for(int i=1;i<=n;i++)
        {
            if(a[i]<minn) minn=a[i];
            if(a[i]>maxx) maxx=a[i];
        }
        cout<<maxx-minn<<endl;
    }
}

B. Make AP

题目链接

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int maxn=500+10;
int n;
int a[maxn];
bool judge(int a,int b,int c)
{
    n++;
    int d,e,f;
    d=b-a;e=c-b;f=c-a;
    if((b+d)%c==0&&(b+d)>=1)
        return true;
    else if(((b-e)%a)==0&&(b-e)>=1)
        return true;
    else if((f%2==0)&&((c-(f/2))%b==0)&&((c-(f/2))>=1))
        return true;
    return false;
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int a,b,c;
        cin>>a>>b>>c;
        if(judge(a,b,c))cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}

C. Division by Two and Permutation

题目链接

题意:n个数的数列a,其中每个数都可以无限除2(向下取整),问在操作后能不能用1~n充满数列a

思路:除2直到它既在1~n以内,又在数列中不存在,此时即可终止。后续的值到达这个数时,这个数就可以继续向下找。用sort排一下序保证我们先把1~n中的数处理掉即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int maxn=500+10;
int n;
int a[maxn];
int vis[maxn];
int flag;
int f(int x)
{
    int ans=0;
    while(x)
    {
        if(x<=n&&vis[x]==0) return x;
        x/=2;
    }
    return x;
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        flag=0;
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            vis[i]=0;

        }
        sort(a+1,a+n+1);
        for(int i=1;i<=n;i++)
        {
            int k=f(a[i]);
            //cout<<"i,k: "<<i<<", "<<k<<endl;
            if(k==0) {cout<<"NO"<<endl;flag=1;break;}
            else vis[k]=1;
        }
        if(flag==0)
            cout<<"YES"<<endl;
    }
    return 0;
}

D. Palindromes Coloring

题目链接

 题意:有长度为n的字符,字符一共可以被染成k种颜色,染完色后的字符位置可以互换,尽量让染后字符 组成的回文串的数量最大,例如现在可以染两种颜色,那么一般情况下我们可以得到个回文串,返回两个串的最小长度。

思路:题目明显满足当回文串长度越短,可以组成的回文串的数量单调不减,用二分来找答案即可。其中判断能否有k串回文串时,因为当我们染色后字符的位置可以互相交换的,因此问题就变成了找相同字符数量的问题。

当我们要求的回文串的长度为奇数时,可以先找一个字符数量为奇数的字符,用来做中间字符,没有字符数量为奇数的字符时可以随便用一个,问题变为两两的找字符的问题。从始至终我们值讨论某个字符的数量的问题即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int maxn=500+10;
int n,k;
int a[maxn];
int vis1[maxn],vis[maxn];
int flag;
int judge(int mid)
{
    for(int i='a'; i<='z'; i++)
        vis[i]=vis1[i];
    for(int i=1; i<=k; i++)
    {
        int sum=mid;

        if(sum%2==1)
        {
            for(int i='a'; i<='z'; i++)
                if(vis[i]%2==1)
                {
                    vis[i]--,sum--;break;
                }
        }
        if(sum%2==1)
        {
            for(int i='a'; i<='z'; i++)
                if(vis[i]>=1)
                {
                    vis[i]--,sum--;break;
                }
        }
        if(sum%2==1) return false;

        for(int j='a'; j<='z'; j++)
        {
            while(vis[j]>=2&&sum>=2)
            {
                vis[j]-=2,sum-=2;
                if(sum==0) break;
            }
            if(sum==0) break;
        }
        if(sum!=0) return false;

    }
    return true;
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        memset(vis1,0,sizeof(vis1));
        cin>>n>>k;
        string str;
        cin>>str;
        for(int i=0; i<n; i++) vis1[str[i]]++;
        int l=1,r=n/k,mid;
        int ans=0;
        while(l<=r)
        {
            mid=(l+r)/2;
            if(judge(mid))
            {
                ans=mid;
                l=mid+1;
            }
            else
                r=mid-1;
        }
        cout<<ans<<endl;

    }
    return 0;
}

E. Masha-forgetful

题目链接

题意:masha需要记一串字符串s长度为m,此前她已经记住了n个长度为m的字符串,问你能不能从masha已经记住的字符串里面找出一些片段来组成她要记住的字符串s,注意片段最小的最小长度为2且可以重复获取,例如121 我们可以同时取 12和21 两个片段

思路:我们可以首先把masha记住的n个字符串处理为2个或3个字符的小“片段”用map保存一下,后续用dp的方式查看某个位置能否用已经存在的“片段”来填充。

dp时,我们用dp【i】=true 表示从i往后(包括i)的位置需要填充。

那么当dp【i】=true且需要记忆的字符串s 从i~i+k的字符片段 存在 时,就可以转移到

dp【i+k+1】了。

注意:只处理两个或三个小片段的原因是因为更长的片段可以由小片段组成;dp【1】=true

#include<bits/stdc++.h>
using namespace std;
#define sz(v) (int)v.size()
typedef long long ll;
const int mod=1e9+7;
const int maxn=1e4+10;

map<string,bool>have;
map<string,tuple<int,int,int>>pos;
void solve()
{
    have.clear();
    pos.clear();
    int n,m;
    cin>>n>>m;
    vector<bool>dp(m+1,false);
    vector<int>pr(m+1);

    for(int i=0;i<n;i++)
    {
        string s;cin>>s;
        for(int j=0;j<m;j++)
        {
            string temp="";
            temp+=s[j];
            for(int k=1;k<=2;k++)//记忆masha能得到的长度位2或3的子串
            {
                if(j+k>=m) break;
                temp+=s[j+k];
                if(!have[temp])
                {
                    have[temp]=true;
                    pos[temp]=make_tuple(j,j+k,i);
                }
            }
        }
    }

    string s;cin>>s;
    dp[0]=true; //设初值
    for(int i=0;i<m;i++)
    {
        string temp="";
        temp+=s[i];
        for(int k=1;k<=2;k++)
        {
            if(i-k<0) break;
            temp=s[i-k]+temp; //相当于取出第i位的前1或2个,检测成功与否
            if(have[temp]&&dp[i-k])//若masha记忆的组合中有,则表明从0到i的串都可表示
            {
                dp[i+1]=true;
                pr[i+1]=i-k;
            }
            if(dp[i+1]) break;
        }
    }
    if(!dp[m])
    {
        cout<<"-1"<<endl;
        return;
    }
    vector<tuple<int,int,int>>ans;
    for(int k=m;k>0;)
    {
        int p=pr[k];
        string temp=s.substr(p,k-p);
        ans.push_back(pos[temp]);
        k=p;
    }
    cout<<ans.size()<<endl;
    reverse(ans.begin(),ans.end());
    for(auto [i,j,k]:ans)
        cout<<i+1<<" "<<j+1<<" "<<k+1<<endl;//下标对齐
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        solve();
    }
}

F. Interacdive Problem

待续。。。。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值