Codeforces Round #823 (Div. 2)(A~D)(模拟,二分,数学,字符串构造)

A. Planets

卫星射击,简单的模拟题

#include<bits/stdc++.h>
using namespace std;
int a[105];
int main()
{
    int t;cin>>t;
    while(t--){map<int,int>mp;
        int n,c;cin>>n>>c;
        for(int i=0;i<n;i++){cin>>a[i];、mp[a[i]]++;}
        int ans=0;
        for(auto i:mp)
            if(i.second>=c)ans+=c;
            else ans+=i.second;
        cout<<ans<<endl;
    }
    return 0;
}

B. Meeting on the Line

题意:每个人到 x0 的所花时间是 ti +| x0 - xi |,求应该把x0设置在哪里

思路:

二分时间,并且check 时间是否合适。最后得到合适的最短时间,用这个最短时间去找每个人能够移动的最大范围的重叠的地方,那么这个重叠的地方就是答案。同时关于怎么check也是找区间,有过有的区间没有重叠的地方,那么这个时间就是不合适的了。

注意:

记得在输出的时候要输出10位,不然会WA

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
double x[100005],t[100005],n,ans;
bool check(double mid){
    double r=1e18,l=0;
    for(int i=0;i<n;i++){
        if(mid<t[i])return 0;
        double time=mid-t[i];
        r=min(r,x[i]+time);
        l=max(l,x[i]-time);
    }
    ans=r;
    return r>=l;
}
signed main()
{
    int T;cin>>T;
    while(T--){
        cin>>n;
        for(int i=0;i<n;i++)cin>>x[i];
        for(int i=0;i<n;i++)cin>>t[i];
        double l=0,r=1e18;//模拟时间
        for(int i=1;i<=100;i++){
            double mid=(l+r)/2;
            if(check(mid)){r=mid;}
            else l=mid;
        }
        check(r);
        cout<<fixed<<setprecision(10)<<ans<<endl;
    }
    return 0;
}

C. Minimum Notation

简单模拟

思路:记录最终输出的答案的0~9的个数,之后从小到大输出

1.把每个数的位置记录下来,从0到9枚举 i 的最后一位

2.之后把从i-1的最后一位到 i 的最后一位中间的数记录

2.1 如果是数字是9,9的个数+1

2.2如果是数字是i,i的个数+1

2.3剩下情况,(该数字+1)的个数+1

之后从小到大输出

代码:

#include<bits/stdc++.h>
using namespace std;
char s[200005],ss[200005];
int main()
{
    int T;cin>>T;
    while(T--){
        cin>>s;
        vector<int>v[10];
        int co[10]={0};
        int n=strlen(s);
        for(int i=0;i<n;i++){
            ss[i]=s[i];
            v[s[i]-'0'].push_back(i);
        }
        int l=0;
        for(int i=0;i<=9;i++){
            int r=v[i].size();
            if(r==0)continue;
            if(v[i][r-1]<l)continue;
            for(int q=l;q<=v[i][r-1];q++){
                if(s[q]==(i+'0'))co[i]++;
                else if(s[q]=='9')co[9]++;
                else co[s[q]-'0'+1]++;
            }
            l=v[i][r-1]+1;
        }
        for(int i=0;i<=9;){
            if(co[i]!=0)cout<<i;co[i]--;if(co[i]<=0)i++;
        }
        cout<<endl;
    }
    return 0;
}

D. Prefixes and Suffixes(字符串构造)

题意:有两个字符串s和t,交换同等长度的s的前缀和t的后缀,问能否使s等于t?

(虽然下面的预备知识是另一种方法,但我没有学会……)

预备知识:next数组代表了最长公共前缀和,即(除了当前字符)前缀(从左往右)和后缀(从左往右)的最长的公共长度,next[i]-1就是这个长度(如果最前面的那个是0的话);如果最前面的next值是-1的话,next记录的就是最长的公共长度。

如下面的例子:next数组求解详解

模式串 a b a b a a a b a b a a
下标 1 2 3 4 5 6 7 8 9 10 11 12
next数组 0 1 1 2 3 4 2 2 3 4 5 6
void getnx(string &t,int *nx){
    for(int i=1,j=0;i<(int)t.size();i++){ //j记录每次nx[]的长度 i从1, j从0开始
        while(j&&t[i]!=t[j])
            j=nx[j-1];
        if(t[i]==t[j])j++;
        nx[i]=j;
    }
}

思路:参考D. Prefixes and Suffixes(字符串/思维/回文串)

设字符串下标从0开始,len=s.size()

从交换中可以看到s1[i]和s2[len-i-1]的相对位置都是不变的,例如下图{b, 2}的相对位置就是不变的,都是对称的

在这里插入图片描述 

因此如果某一对是偶数次,那么符合题意

如果某一对是奇数次,

           如果两个字符不同的话,那一定是不行的
           如果是一样的话,只有一次可以,就是中间的时候

代码:

#include<bits/stdc++.h>
using namespace std;
string s1,s2;
map< pair<char,char>,int>mp;
int main()
{
    int T;cin>>T;
    while(T--){
        mp.clear();int n;cin>>n;
        cin>>s1>>s2;
        for(int i=0;i<n;i++){
            char a=s1[i],b=s2[n-i-1];
            if(a>b)swap(a,b);
            mp[{a,b}]++;
        }
        int qi=0;bool flag=1;
        for(auto i:mp){
            if(i.second%2==0)continue;
            if(i.first.first!=i.first.second){flag=0;break;}
            else{qi++;if(qi>1){flag=0;break;}}
        }
        if(flag)cout<<"YES\n";
        else cout<<"NO\n";
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zy98zy998/article/details/127112470