xtu oj 数字
文章目录
- 回顾
- 代码
- 思路
回顾
- A+B III
- 问题 H: 三角数
- 问题 G: 3个数
- 等式 数组下标查询,降低时间复杂度
- 1405 问题 E: 世界杯
- xtu 数码串
- xtu oj 神经网络
- xtu oj 1167 逆序数(大数据)
- xtu oj 原根
- xtu oj 不定方程的正整数解
- xtu oj 最多的可变换字符串
- xtu oj String I
- xtu oj 字母序列
- xtu oj 分段
- xtu oj 完全平方数II
- xtu oj 连接字符串
- xtu oj 2021
代码
#include<stdio.h>
int main(){
int t;
scanf("%d",&t);
while(t--){
int n,k;
scanf("%d%d",&n,&k);//输入 n 和 k
int cnt=0;//存操作的次数
int temp=n;//临时变量存 n ,其实直接用 n 也行
while(1){
if(temp<k){//满足条件就跳出循环,严格小于
break;
}
if(temp%10==0){//尾数是 0,操作次数只需要一次,可以把全部的零去掉
cnt++;
while(temp%10==0){
temp/=10;
}
}else{//尾数不是 0
for(int i=1;i<=9;i++){//枚举个位数
if((temp-i*k)%10==0&&i*k<=temp){//这里的限制条件需要注意一下
temp-=i*k;
cnt+=i;
break;
}
}
if((temp>=k)&&(temp%10!=0)){//整除降低时间复杂度
int hhh=temp/k;
cnt+=hhh;
temp-=hhh*k;
}
}
}
printf("%d %d\n",cnt,temp);
}
return 0;
}
思路
复习 SOA 复习不下去了,写一写算法题。首先写了一个超时的代码
#include<stdio.h>
int main(){
int t;
scanf("%d",&t);
while(t--){
int n,k;
scanf("%d%d",&n,&k);//输入 n 和 k
int cnt=0;//存操作的次数
int temp=n;//临时变量存 n ,其实直接用 n 也行
int i=0;
while(1){
if(temp%10==0){//尾数是 0
cnt++;
while(temp%10==0){
temp/=10;
}
}else{//尾数不是 0
while((temp-k*i)%10!=0&&temp>=k){
i++;//应该就是这里超时了,因为 n 是 10^9 ,能接受的时间复杂度是 10^8 ,所以应该要优化一下
}
cnt+=i;
temp-=k*i;
}
if(temp<k){
break;
}
}
printf("%d %d\n",cnt,temp);
}
return 0;
}
比较直观,没想到直接就超时了。难道是看 n 能不能整除 k 吗,感觉优化的话,就是用除法这种去代替原来超时代码里面的 i++
,i++
估计有差不多 10^9
的时间复杂度。我们经过多少次操作可以使得 n
可以被 10
整除,比如说 n
是一个很大的数字,9999999999
,9
个 9
,假设 k
是一个质数 7
,会不会经过很多次减法,还是不能让 n
可以整除 10
,那假设我们直接用除法,那时间复杂度可以降到 O(1)
这样子,n/k
但是无法保证这就是正解,比如说 n=333,k=3
,直接就是 n/k==111
,但是这个不是正解。正解是 5
次。
这个题放在贪心这个章节。应该是要一边维护 n
,一边判断,关键就是这个判断的标准是什么。我感觉是先看能不能整除,能整除的话就把 n
减小一些,然后看n
能不能整除 10
,我试一试。这样子好像运行程序的时候直接卡住了。
不会写了,搜到了一篇题解,XTUOJ杂题烩。还得是题解的思路比较好。
不过为啥我按照这个思路写,只有 33
分呢。发现自己主要是没想到枚举个位数这一步,想到了整除降低时间复杂度。之前看网课,里面说其实思路大家都差不多,就整体的思路,就比如说一开始直接模拟就超时这种思路,比较直观的,然后一些细节才真正决定能不能过掉这题。或者拿尽可能高一点的分数,不过 c
语言考试没有 33
分这种,是 acm
模式,某个题要么 100
,要么 0
。看了题解的代码,感觉差不多。奇怪了。有没有读者知道问题出在哪里。
#include<stdio.h>
int main(){
int t;
scanf("%d",&t);
while(t--){
int n,k;
scanf("%d%d",&n,&k);//输入 n 和 k
int cnt=0;//存操作的次数
int temp=n;//临时变量存 n ,其实直接用 n 也行
while(1){
if(temp%10==0){//尾数是 0
cnt++;
while(temp%10==0){
temp/=10;
}
}else{//尾数不是 0
for(int i=1;i<=9;i++){//枚举个位数
if((temp-i*k)%10==0){
temp-=i*k;
cnt+=i;
break;
}
}
if(temp>=k&&temp%10!=0){//整除降低时间复杂度
int hhh=temp/k;
cnt+=hhh;
temp-=hhh*k;
}
}
if(temp<k){
break;
}
}
printf("%d %d\n",cnt,temp);
}
return 0;
}
交了一下题解的做法,能过,为啥我这个就过不了呢。那能过 33
的数据点又是什么意思呢,这里也不存在超出数据范围的情况。不行,我一定要把这个搞清楚。
嗷嗷我知道了。循环里面的限制条件没有限制严格,可能会出现负数的情况,之前的博客也有讲过,就是计算机负数进行取余运算的时候和我们理解的数学上的不太一样。