CSP-J省一班夏令营模拟赛三补题报告

目录

一、AC情况

二、赛中概况

三、解题报告

问题一:操作队列(queue)

情况:

题意:

题解:

正解代码:

问题二:数值计算(calc)

情况:

题意:

题解:

正解代码:

问题三:益智游戏(game)

情况:

题意:

题解:

正解代码:

问题四:异或函数(function)

情况:

题意:

题解:

正解代码:

 四、总结


一、AC情况

全部四道题赛后补题AC

二、赛中概况

第一道题就卡住了,有思路,但代码一直调不对。最后打了个表,10^9的数据量内存原地爆炸爆掉,第二题用不到20分钟秒了,但是freopen写错了(……)。后面两题直接连题都没读。

三、解题报告

问题一:操作队列(queue)

情况:

赛后补题AC

题意:

一个队列,初始有a,b,c,d,e五个元素,进行多次操作,每次将队首元素出队,并将该元素入队两次,给定一个数字n,求第n次操作时弹出的队首元素。

比赛时思路是对的,但代码没调出来。

题解:

第一种思路,直接用队列进行模拟。但不出意外的话肯定超时。

因此可以找规律。

不难看出,该队列是这样的:

阶段数序列长度
1abcde5
2aabbccddee10
3aaaabbbbccccddddeeee20
4……40

那么我们可以得出一下思路: 

求要查询的点在第几阶段,就让总长度n不断减去5、10、20、40……

求出在低级阶段,就很容易得出答案了。

正解代码:

#include<iostream>
using namespace std;
int n;
int x=5;  //每阶段的长度
int y=1;  //当前阶段每个字母的个数
int main(){
    cin>>n;
    while(n-x>0){
        n-=x;
        x*=2;
        y*=2;
    }
    char c=(n+y-1)/y+'a'-1;  //答案
    cout<<c;
    return 0;
}

问题二:数值计算(calc)

情况:

赛后补题AC

题意:

给定a,b,c,求出一个最小的k,使k满足(k​^a)​​%b=c。如果k不存在,输出-1。

不要问我这个标题里a和l为什么标红,问就是比赛时freopen里打反了。

题解:

这题其实非常简单,只需要简单枚举k,用快速幂求出(k^a)%b,再判断是否与c相等即可。

一个需要关注的点在于,k最大不超过多少?

因为(k^a)%b=[(k%b)^a]%b,所以k>=b没有意义,会被模掉,所以k最大不超过,也不会等于b,即k<b。

那么这题就非常好写了。

正解代码:

#include<iostream>
#include<cstdio>
using namespace std;
long long n,a,b,c;
long long ksm(long long a,long long b,long long m){
	long long ans=1%m;
	while(b){
		if(b&1){
			ans=(ans*a)%m;
		}
		b>>=1;
		a=(a*a)%m;
	}
	return ans;
}
int main(){
	cin>>n;
	while(n--){
		cin>>a>>b>>c;
		if(c>b){  //因为要模b,所以c不可能大于b,直接输出-1
		    cout<<-1<<"\n";
		    continue;
		}
		for(int i=1;i<b;i+=2){
			if(ksm(i,a,b)==c){
				cout<<i<<"\n";
				break;
			}
		}
	}
	return 0;
}

问题三:益智游戏(game)

情况:

赛后补题AC

题意:

有n辆卡车,第i辆卡车有ti千克的货物,限重是wi。当车上货物的重量大于限重时,车子就会报废。我们的卡车是第一辆,我们可以把我们卡车上的货物放到别人的车上,使别人的卡车报废,让我们的排名更高。问我们能达到的最高名次是多少(游戏名次计算规则:在没有报废的车中,按照货物重量降序

题解:

这题使用贪心。

我们要破坏名次更高,且花费最少的卡车。

在报废卡车的过程中,因为货物放到了别人的车上,我们的排名有可能会降低,因此要动态维护排名。

使用优先队列进行维护即可。

正解代码:

#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
//存储两个值,优先按照ti排序,确定谁名次更高
pair<long long,long long> p[300010];
int n;
long long t,w;  //自己的,单独维护
priority_queue<long long,vector<long long>,greater<long long> > q;  //小根堆
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n>>t>>w;
    for(int i=2;i<=n;i++){
        cin>>p[i].first>>p[i].second;
    }
    sort(p+2,p+1+n);  //确定谁名次更高
    long long ans=0x3f3f3f3f;
    int i=n;
    while(1){
        //找到排名更高的放入优先队列
        for(;i>=2&&p[i].first>t;i--){
            //tmp存储需要多少可以使该车报废
            long long tmp=p[i].second-p[i].first+1;
            q.push(tmp);
        }
        ans=min(ans,(long long)q.size()+1);
        if(!q.empty()&&t>=q.top()){
            t-=q.top();
            q.pop();
        }
        else{
            break;
        }
    }
    cout<<ans;
    return 0;
}

问题四:异或函数(function)

情况:

赛后补题AC

题意:

在一个长度为n的数组中,定义异或函数:

img

 其中⨁指的是异或。

给定区间[l,r],求出a[l],a[l+1],⋯,a[r]的子区间中异或函数f的最大值是多少。

题解:

分析:

如:1 2 4 8

1 2 4 8                                                                                                                                                 3 6 12                                                                                                                                                   5 10                                                                                                                                                      15

类似于杨辉三角。

实现:

使用dp。

设数组f,f[i][j]表示第i层的第j个数字。

类比杨辉三角,推出f[i][j]=f[i-1][j-i]^f[i-1][j]。

递推求出所有f[i][j]。

设数组dp,dp[i][j]表示从第i个数字开始,长度为j的最大值。

用动态规划求出dp[i][j]。

最后进行查询即可。

正解代码:

#include<iostream>
using namespace std;
int f[5050][5050],dp[5050][5050],n;
int main(){
    ios::sync_with_stdio(false);  //关闭输入输出流,不然容易时间超限
    cin.tie(0);
    cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>f[1][i];
        dp[i][1]=f[1][i];
    }
    for(int i=2;i<=n;i++){
        for(int j=1;j<=n-i+1;j++){
            f[i][j]=f[i-1][j]^f[i-1][j+1];
            dp[j][i]=max(f[i][j],max(dp[j][i-1],dp[j+1][i-1]));
        }
    }
    int q;
    cin>>q;
    int l,r;
    while(q--){
        cin>>l>>r;
        cout<<dp[l][r-l+1]<<"\n";
    }
    return 0;
}

 四、总结

这次比赛可以说打的很不好。第一题打表爆内存,第二题犯了十分低级的错误,后两题直接没看。

应合理分配时间,暴力不要想着拿全分,注意检查。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值