程序设计第二次CSP模测

程序设计第二次CSP模测

to sum up
模测只拿了130,超级遗憾,第一题因为少想了一种情况爆0了。感觉独自思考问题的能力以及做题经验有所欠缺。列一下模测题目。

A题

对于一个序列,判断是否存在一个数 ,使得一些数加上 ,一些数减去 ,一些数不变,使得整个序列中所有的数相等,其中对于序列中的每个位置上的数字,至多只能执行一次加运算或减运算或是对该位置不进行任何操作。

Sample Input and Output

Input

输入第一行是一个正整数 表示数据组数。 接下来对于每组数据,输入的第一个正整数 表示序列 的长度,随后一行有 个整数,表示序列 。

2
5
1 2 3 4 5
5
1 2 3 4 5

Output

输出共包含 行,每组数据输出一行。对于每组数据,如果存在这样的K,输出"YES",否则输出“NO”。(输出不包含引号)

NO
NO

需要注意的就是数据范围:
在这里插入图片描述
需要开long long

解题思路及代码

#include <iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
using namespace std;

const int MAX= 1e5;

int t,n;
long long a[MAX];
long long T[MAX];
int num;

void whe(long long u)
{
    for(int i=0;i<num;i++)
    {
        if(u==T[i])
            return;
    }
    T[num]=u;
    num++;
}

int main()
{
    cin>>t;
    for(int i=0;i<t;i++)
    {
        num=0;
        cin>>n;
        for(int j=0;j<n;j++)
        {
            cin>>a[j];
            whe(a[j]);
        }
        if(num<3)
            cout<<"YES";
        else if(num==3)
        {
            long long Max=max(max(T[0],T[1]),T[2]);
            long long MIN=min(min(T[0],T[1]),T[2]);
            if((Max+MIN)==2*T[0] || (Max+MIN)==2*T[1] || (Max+MIN)==2*T[2])
                cout<<"YES";
            else
                cout<<"NO";
        }
        else
            cout<<"NO";
        if(i!=t-1)
            cout<<endl;
    }
    return 0;
}

总结:

好不容易躲过了数据范围的坑,却没考虑到序列的值可以都一样。
思路很简单,主要是计数,如果序列只有两个值或者都一样,一定可以。如果有三种值,需要计算这三个值是否形成等差数列。大于三个值则一定不可以。

B题

现在给定一个字符串,字符串中包括26个大写字母和特殊字符’?’,特殊字符’?'可以代表任何一个大写字母。现在TT问你是否存在一个位置连续的且由26个大写字
母组成的子串,在这个子串中每个字母出现且仅出现一次,如果存在,请输出从左侧算起的第一个出现的符合要求的子串,并且要求,如果有多组解同时符合位置最靠左,则输出字典序最小的那个解!如果不存在,输出-1!
说明:字典序 先按照第一个字母,以 A、B、C……Z 的顺序排列;如果第一个字母一样,那么比较第二个、第三个乃至后面的字母。如果比到最后两个单词不一样长(比如,SIGH 和 SIGHT),那么把短者排在前。

Sample Input and Output

Input

输入只有一行,一个符合题目描述的字符串。输

ABC??FGHIJK???OPQR?TUVWXY?

Output

输出只有一行,如果存在这样的子串,请输出,否则输出-1

ABCDEFGHIJKLMNOPQRSTUVWXYZ

整体思路及代码:

主要用尺取法,先选定前26个字母,统计每个字母的个数和 ?的个数。需要观察两个值,一个是个数为0的字母的数量,另一个是 ? 的个数。如果两个值相等,则满足条件。如果不满足,两个边界l和r同时有益,更新数量值。当满足条件时,从26个字母数组中,将数组值为0的字母按序输出。

#include <iostream>
#include<string>
#include<algorithm>
using namespace std;
int l,r;
string list;
int num1,num2;
int a[26];
void init()
{
    for(int i=0;i<26;i++)
        a[i]=0;
    num1=0;
    num2=0;
    for(int i=0;i<26;i++)
    {
        if(list[i]=='?')
            num2++;
        else
            a[list[i]-65]++;
    }
    for(int i=0;i<26l;i++)
        if(a[i]==0)
        {
            num1++;
        }
}
void move()
{
    if(list[l]=='?')
        num2--;
    else
    {
        a[list[l]-65]--;
        if(a[list[l]-65]==0)
            num1++;
    }
    l++,r++;
    if(list[r]=='?')
        num2++;
    else{
        if(a[list[r]-65]==0)
            num1--;
        a[list[r] - 65]++;
    }
}
int main()
{
    cin>>list;
    init();
    int n=list.size();
    l=0, r=25;
    while(num1!=num2)
    {
        if(r==n-1)
            break;
        move();
    }
    //输出
    int tar=0;
    if(r==n-1 && num1!=num2)
    {
        cout << -1;
        return 0;
    } else{
        for(int i=0;i<26;i++)
        {
            if (list[l + i] == '?')
            {
                for(int k=tar;k<26;k++)
                    if(a[k]==0)
                    {
                        cout<<(char)(k+65);
                        tar=k+1;
                        break;
                    }
            } else
                cout<<list[l + i];
        }
    }
    return 0;
}

C题 奇妙的序列

自然增长序列1 12 123 1234 12345… 需要查询该序列第n项的值并输出。

Sample Input and Output

Input

输入由多行组成。
第一行一个整数q表示有q组询问(q<500)
接下来第i+1行表示第i个输入 ,表示询问第ki项数字。(k<1e18)

5
1
3
20
38
56

Output

输出包含q行。第i行输出对询问ki的输出结果。

1
2
5
2
0

解题思路及代码

整个过程分为三步,第一步是将原自然增长序串拆分,从1到第一次出现k定为第k个子串。然后用二分法确定输入的数w在第几个子串中,(利用等差数列求前n项和的方法)。最后确定w在子串中具体属于哪一个数字的哪一位。

#include<iostream>
#include<vector>
using namespace std;
const long long N = 1e9;
long long l,r,mid,ans;
//二分法确定子序列
long long getlist(long long x)
{
    long long pwr=10,Nsum=0,sum=0,n=0,d=1;
    while(x>pwr-1)
    {
        n=pwr-pwr/10;
        Nsum+=(sum+d)*n+n*(n-1)/2*d;
        sum+=n*d;
        pwr*=10;
        d++;
    }
    n=x-pwr/10+1;
    Nsum+=(sum+d)*n+n*(n-1)/2*d;
    return Nsum;
}

long long speci(long long x)
{
    l=0;
    r=N;
    while(l<=r)
    {
        mid=(l+r)/2;
        if(getlist(mid)<x)
            ans=mid,l=mid+1;
        else r=mid-1;
    }
    x-=getlist(ans);
    return x;
}
//二分法确定n在子序列中的位置
long long findNthDigit(long long p)
{
    long long tmp=speci(p);
    //cout<<'!'<<endl;
    long long m=1,len=0,n=0,y=0,sum=0;
    while(tmp)
    {
        m*=10;
        n=m-m/10;
        len++;
        if(tmp>n*len)
        {
            sum+=n;
            tmp-=n*len;
        } else{
            sum=sum+tmp/len;
            y=tmp%len;
            break;
        }
    }
    if(y==0)
        return sum%10;
    else
    {
        sum++;
        while(len!=y)
        {
            len--;
            sum/=10;
        }
        return sum%10;
    }
}
long long n,k;
int main()
{
    cin>>n;
    //init();
    for(int i=0;i<n;i++)
    {
        cin>>k;
        //cout<<'!'<<endl;
        cout<<findNthDigit(k)<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值