CSP测试2

时间:2020-04-17
本文章向大家介绍CSP测试2,主要包括CSP测试2使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

  总算是把题目全部都做出来了,但是最后系统判分的时候却傻眼了,三个题都没有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\n",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;
//    } 
    
} 

原文地址:https://www.cnblogs.com/Xu-SDU/p/12695147.html