zoukankan      html  css  js  c++  java
  • CSP测试M2

      总算是把题目全部都做出来了,但是最后系统判分的时候却傻眼了,三个题都没有AC,要么有些数据点runtime errror,要么直接就wrong answer,实在是令人揪心啊!最后复盘的时候才发现确实是出了一点纰漏,但是明明可以避免的了,我却全中招了,不得不令我反思啊!A题是漏掉了一个判断条件,在设计数据的时候也没有发现这个漏洞,就这样wrong answer了,B题有些数据点出现了runtime error,但是后来在VJ上补题的时候一样的代码最后还都AC了。C题是直接wrong answer了,后来发现也是欠考虑了。

    A-

    思路分析:

      读题我们发现这道题的思路并不难,要求能够加或减一个数K或不操作得到一个相等的数列,我们不难发现,当这个序列不同的元素小于等于二的时候是一定能够实现的,不同元素为三的时候要求这三个数形成一个等差数列,除了上述情况,其他情况都是不可能满足题意的。

    源代码如下:

    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    int t;
    int n;
    long long a[10];
    int m;
    
    bool check(long long temp){
        for(int i=0;i<m;i++){
            if(temp==a[i]){
                return false;
            }
        }
        return true;
    }
    
    int main(){
        
        scanf("%d",&t);
        
        
        for(int ii=0;ii<t;ii++){
            scanf("%d",&n);
            m=0;
            if(n<=2){
                long long temp;
                for(int i=0;i<n;i++){
                    scanf("%lld",&temp);
                }
                cout<<"YES"<<endl;
                continue;
            }else{
                m=0;
                scanf("%lld",&a[m]);
                m++;
                long long temp;
                
                    for(int i=1;i<n;i++){
                        scanf("%lld",&temp);
                        if(m<=5){
                            if(check(temp)){
                                a[m]=temp;
                                m++;
                            }
                        }
                        
                    }
                
                if(m>=4){
                    cout<<"NO"<<endl;
                    continue;
                }else{
                    if(m<=2){
                        cout<<"YES"<<endl;
                        continue; 
                    }
                    sort(a,a+m);
                    if(2*a[1]==a[0]+a[2]){
                        cout<<"YES"<<endl;
                        continue; 
                    }else{
                        cout<<"NO"<<endl;
                        continue;
                    }
                }
                
            }
            
        }
        
    } 

    B-

    思路分析:

      这道题使用可以使用尺取法来解决。按照题意,我们需要先从头读取26长度的字符串,然后不断调整这个head和tail,使其满足题设,然后输出第一个满足要求的并且字典序最小的答案。以下代码使用了数组a[26]来记录对应的每个字母的个数,m记录在这个长度内的'?'的个数。check()函数判断是否满足要求。首先使用一个初始化函数来先读取开始的26个字母,然后每次head++、tail++,并调整数组a,每次check一遍,符合要求则输出,程序结束。

    以下是源代码:

    #include<iostream>
    #include<string>
    #include<cstring>
    
    using namespace std;
    
    int a[26];// 0 or 1
    string str;
    int m;//num of ?
    int n[26];
    int lack;// currenet str lack num
    
    int head,tail;
    
    bool check(){
        lack=0;
        for(int i=0;i<26;i++){
            if(a[i]==0){
                n[lack]=i;
                lack++;
            }
        }
        return lack==m;
    }
    
    void init(){
        m=0;
        head=0;tail=26;
        lack=0;
        for(int i=0;i<26;i++){
            if(str[i]=='?'){
                m++;
            }else{
                a[str[i]-'A']++;
            }
        }
    }
    
    void fuc1(){//head++
        if(str[head]=='?'){
                m--;
            }else{
                a[str[head]-'A']--;
            }
        head++;
    }
    
    void fuc2(){//tail++
        if(str[tail]=='?'){
                m++;
            }else{
                a[str[tail]-'A']++;
            }
        tail++;
    }
    
    void output(){
        int tem=0;
        for(int i=0;i<26;i++){
            if(str[head+i]=='?'){
                cout<<(char)('A'+n[tem]);
                tem++;
            }else{
                cout<<str[head+i];
            }
        }
        cout<<endl;
    }
    
    int main(){
        cin>>str;
        if(str.size()<26){
            cout<<-1<<endl;
            return 0;
        }
        init();
        while(tail<=str.size()){
            if(check()){
                output();
                return 0;
            }
    //        for(int i=0;i<26;i++){
    //            cout<<a[i];
    //        }
    //        cout<<endl;
            fuc1();
            fuc2();
        }
        
    //    cout<<"at the end"<<endl;
        cout<<-1<<endl;
        return 0;
    }

    C-

    思路分析:

      首先我们将序列分为n个区间,每个区间是由1-n组成的序列,总体的思路就是先确定第q项在哪一个区间,然后再确定区间内的位置。

      通过观察可以看出来,在1-9的时候,每个区间长度形成一个d=1的一个等差数列,10-99时,由于出现了两位数,区间仍形成一个等差数列,但是公差d++了,以此类推,由此我们可以知道区间长度是多个等差数列构成的。我们要到到这样的目的,给出区间数,然后求出这个区间的前面的总位数(包括自己),其实是将每个区间长度看为数列的项,求前向和Sn。根据数学知识我们可以得到计算公式。在每一个等差数列中Sn=n*a1+(n*(n-1)*d)/2, An=a1+(n-1)*d 。分别算出来不同区段的长度累加便可以得到第i个区间的前向和Sn。解决了这个问题剩下来就好解决了。我们可以通过二分的办法来确定第q项在哪个区间内,然后得到区间内的项数,再次使用二分的方法确定其在区间内的位置即可求出题解。

     以下为源代码:

    #include<iostream>
    #include<cstring>
    #include<string>
    #include<cmath> 
    #define ll long long 
    using namespace std;
    
    ll Sn(ll a1,ll n,ll d){
        return n*a1+(n*(n-1)*d)/2;
    }
    
    ll An(ll a1,ll n,ll d){
        return a1+(n-1)*d;
    }
    
    //计算第x个区间的前向区间位数和sum 包括x (利用多个等差数列的性质) 
    ll fuc1(ll x){
        ll tem=x;
        ll temp,cnt,a1,d,sum,n,alast,dlast;
        temp=10;cnt=0;a1=1;sum=0;d=1;dlast=1;alast=0;
        //Sn = n*a1+n*(n-1)/2 * d
        while(temp<=x){
            n=temp-cnt-1;
            sum+=Sn(a1,n,d); 
            alast=a1;dlast=d;
            a1=An(a1,n,d)+d+1;
            d++;temp*=10;cnt+=n;
        }
        temp/=10;
    
        n=x-temp+1;
    //    d=dlast;a1=alast;
        sum+=Sn(a1,n,d);
        return sum;
    }
    
    ll fuc2(ll x)
    {
     ll temp=x;
     ll sum=0,n=0,d=0,cnt=1,dlast=1,alast=0;
     while(temp>=10){
      cnt*=10;
      d++;
      n=cnt-cnt/10;
      sum=sum+n*d;
        temp/=10;
     }
         d++;
     n=x-cnt+1;
     sum=sum+n*d;
     return sum;
    }
    
    int main(){
        ll n;
        cin>>n;
        for(ll i=0;i<n;i++){
            ll q;
            cin>>q;
            ll left,right,mid;
            left=0;right=1e9;mid=(left+right)/2;
            ll ans=0;
            while(left<=right){
                ll temp=fuc1(mid);
                if(temp<q){
                    ans=mid;
                    left=mid+1;
                    mid=(left+right)/2;
                }else{
                //    ans=mid;
                    right=mid-1;
                    mid=(left+right)/2;
                }
            }
        ll sum=fuc1(ans);
      q=q-sum;
      left=0,right=ans+1,ans=0;
      while(left<=right){
       mid=(left+right)/2;
       ll sum=fuc2(mid);
       
       if(sum<q)
       {
        ans=mid;
        left=mid+1;
       }
       else
       {
        right=mid-1;
       }
      }
      sum=fuc2(ans);
      q-=sum;
      ans++;
      
      string str=to_string(ans);
      printf("%c
    ",str[q-1]);
     //cout<<str[q-1]<<endl;
        } 
    //for(int i=0;i<10;i++){
    //        ll q;
    //        cin>>q;
    //        ll left,right,mid;
    //        left=0;right=q;mid=(left+right)/2;
    //        ll ans=fuc1(q);
    //        cout<<ans<<endl;
    //    } 
        
    } 
  • 相关阅读:
    PHP touch() 函数
    PHP tmpfile() 函数
    PHP tempnam() 函数
    PHP symlink() 函数
    PHP stat() 函数
    pt-table-sync
    P4233 射命丸文的笔记
    C# Task.Run 和 Task.Factory.StartNew 区别
    C# Task.Run 和 Task.Factory.StartNew 区别
    SourceYard 制作源代码包
  • 原文地址:https://www.cnblogs.com/Xu-SDU/p/12695147.html
Copyright © 2011-2022 走看看