日期: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 位玩家,每位玩家有一个分数 ai,现在需要将 n 为玩家进行分组,
分组之后每个组将获得一个小组分数序列 。小组分数为小组分数序列中,没有出现过的、最小的自然数。
2、比赛中的思考
第一遍没有读懂,又仔细读了一遍,推了推样例,懂了,一眼丁真:淼题。
不过作为蒟蒻的我,过了个大淼题也激动的不得了(笑
3、解题思路
用桶b[N]来记录每个数出现的次数(不会爆)。从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,要求使:
对于不满足要求的数,可以更改,求最小更改次数。
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]
小可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]));