CSP-J模拟赛一补题报告

本文是作者参加CSP-J模拟赛的补题报告,详细分析了四道题目——数字降级、分组、抢夺地盘和闯关。在数字降级中,通过模拟判断质因子,因TLE损失分数;分组问题采用桶排序快速求解小组分数;抢夺地盘简化为两个LIS问题;闯关问题采取贪心策略,获得80分。
摘要由CSDN通过智能技术生成

日期:2023-09-30 周六
学号:S00338


一、简述


总分数:290
T1【数字降级down】:90
T2【分组group】:100 
T3【抢夺地盘seize】:20 
T4【闯关barrier】:80 


二、比赛过程

    这次我直接按着题目顺序做的。
    T1改了一版,结果还是太麻烦,特别容易时超,差点放弃,最后估计最后一点TLE了。
    T2没什么,很容易想到正解,挺水的。
    T3我没有仔细分析,没想到LIS,  想到了也不一定满分,本蒟蒻手打二分太容易崩
    T4的话,我想了想dp,但觉得有点过于复杂了,于是贪心,居然贪了80(喜

三、题目分析


【数字降级down】


1、题目大意


    给出正整数n,输出除以一个它的因子是否是素数。
    人话:判断有没有质因子。

2、比赛中的思考


    赛时题解(雾:
        扫了一眼题目,感觉还行。
        仔细看看,发现得稍微思考思考。
        然后仔细读题发现可以模拟一下。

        for(int i=n;i>=1;i--){
           if(n%i==0&&p(n/i)){//i是n的因子,且n/i是素数    
                n/=i;
                ans++;
            }
        }


        于是自信的输入10000000000(题目中的最大值),结果TLE
        因为输入只有一个n,且次数与n的质因子有关,于是尝试手算n=1,2,3,4……的值。
        发现可以这么写:

        for(int i=2;i<n;i++){//枚举<n的所有素数(不<=n是因为防止n是素数)
            if((n%i==0)&&p(i)){//如果i是质因子
                n/=i;
                sum++;
                if(p(n)==0){//如果n/i了之后不是
                    break;    
                }
            }
        }


        也不知道行不行。
  
 结果不知道哪里少了10分。
    怀疑一开始两个for中的int i炸了,导致负数,TLE了。 

3、解题思路


    因为自己被T1整的有点懵,导致没有发挥出来,打代码时有点傻,其实就是判断素数,没什么好说的。

4、AC code:(主要代码)

bool p(long long x){
    for(long long i=2;i*i<=x;i++)  if(n%i==0)  return 0;
    return 1;
}
int main(){
    scanf("%lld",&n);
    if(p(n))  printf("0");
    else  printf("1");
    return 0;
}
//其实代码肥肠的简单呐!

【分组group】


1、题目大意


    小可总共召集了 n 位玩家,每位玩家有一个分数 a​i,现在需要将 n 为玩家进行分组,
    分组之后每个组将获得一个小组分数序列 。小组分数为小组分数序列中,没有出现过的、最小的自然数。

2、比赛中的思考


    第一遍没有读懂,又仔细读了一遍,推了推样例,懂了,一眼丁真:题。
    不过作为蒟蒻的我,过了个大淼题也激动的不得了(笑

3、解题思路


    用桶b[N]来记录每个数出现的次数(0<=ai<=1000不会爆)。从1开始遍历(0开始不行,因为要访问i-1)。
    (1)if i出现次数==i-1出现次数,continue
    (2)if i出现次数<i-1出现次数,sum计算无法分配i的其它i-1序列的分数。
    (3)if i出现次数>i-1出现次数,由于i由i-1决定,所以b[i]=b[i-1];

4、AC code:

scanf("%d",&n);
for(int i=1;i<=n;i++){
    scanf("%d",&a[i]);
    b[a[i]]++;
}
for(int i=1;i<=1001;i++){
    if(b[i]-b[i-1]<0)sum+=i*(b[i-1]-b[i]);
    if(b[i]-b[i-1]>0)b[i]=b[i-1];
}
printf("%d",sum);

【抢夺地盘seize】


1、题目大意


    给出P与数组a,要求使:a[1]<......<a[P-1]<a[P]>a[P+1]>......>a[n]
    对于不满足要求的数,可以更改,求最小更改次数。


2、比赛中的思考


    我想的太简单了。直接两个for判断大小去了。结果所有样例都过了。
    我一看,嚯!野生大水题!切掉!
    然后开心的20pts……
    不过居然竟然还能过20pts(逃


3、解题思路


    大体思路就是两个LIS,一个最长不下降,一个最长不上升,最后用总数一减长度再+1(P算了两次)。


4、AC code:

f[++cnt]=a[1];
for(int i=2;i<p;i++){
if(a[i]>=f[cnt]){
    f[++cnt]=a[i];
}
else{
    int l=1,r=cnt;
    while(l<r){    
        int mid=(l+r)>>1;
        if(a[i]<f[mid])  r=mid;
        else  l=mid+1;
    }
        f[r]=a[i];
}    
if(a[p]>=f[cnt])  cnt++;
else  a[p]=1e9+1;

ans=p-cnt;
cnt=1;
f[1]=a[p];
for(int i=p+1;i<=n;i++){
    if(a[i]<=f[cnt]){
        f[++cnt]=a[i];
    }
    else{
        int l=1,r=cnt;
        while(l<r){
            int mid=(l+r)>>1;
            if(a[i]>f[mid])  r=mid;
            else  l=mid+1;
        }
        f[r]=a[i];
    }
}
printf("%lld",ans+((n-p)-cnt+1));

【闯关barrier】


1、题目大意


    小可小达分别在两个赛道上进行比赛,各有n个关卡,每个关卡离顶点距离为ai,他们每次的移动距离m, 以及开挂时的移速k,互相给外挂的距离q。


2、比赛中的思考


    OK啊兄弟们,我这个题dp觉得太难,就直接贪心力,居然最后贪了80pts


3、解题思路


    三维dp数组,分别为小可关卡位置,达达关卡位置,神器在谁那里[0/1]
    f[i][j][0/1]=小可i达达j关使用神器最小次数 
    分别枚举3个维度,然后就可以枚举小可与达达分别拿神器的情况,每种情况又包括达达或小可可以不用神器的小情况。


4、AC code

主要代码:

memset(f,0x3f,sizeof(f));
    f[0][0][0]=0,f[0][0][1]=1;
    for(int step=0;step<=2*n;step++){
        for(int j=0;j<=min(n,step);j++){
            //j为达达走过的关卡 
            int i=step-j;//i指小可走过的关卡 
            if(i>n){
                continue;//小可不能走>n关 
            }
            for(int k=0,r=0;r<=2;k++,r++){
                //枚举第三维度,原地传递,0<==> 1可以相互求min 
                k=r%2;//k在0-1之间滚动 
                if(abs(a[i]-b[j])<=q){//两人之间的距离可以继续传递 
                    f[i][j][k^1]=min(f[i][j][k^1],f[i][j][k]+1);
                }//i,j在0/1情况下,交换次数+1或者当前最小值 
                if(k==0){//道具在小可手里 
                    f[i+1][j][k]=min(f[i+1][j][k],f[i][j][k]);
                    if(b[j+1]-b[j]<=m){//达达可以不用神器 
                        f[i][j+1][k]=min(f[i][j+1][k],f[i][j][k]);
                    }
                }
                else{//道具在达达手里 
                    f[i][j+1][k]=min(f[i][j+1][k],f[i][j][k]);
                    if(a[i+1]-a[i]<=m){//小可可以不用神器 
                        f[i+1][j][k]=min(f[i+1][j][k],f[i][j][k]);
                    }
                }
            } 
        }
    }
    printf("%d\n",min(f[n][n][0],f[n][n][1]));

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值