听说我已经进入NOJ的水题区了呢
/斜眼笑/斜眼笑/斜眼笑
- NOJ 26# 羊羊聚会
扩展欧几里得问题………… /挠头
先上一段欧几里得问题的证明:
gcd(a,b) = gcd(b,a mod b) (不妨设a>b 且r=a mod b ,r不为0)
证法一
a可以表示成a = kb + r(a,b,k,r皆为正整数,且r<b),则r = a mod b
假设d是a,b的一个公约数,记作d|a,d|b,即a和b都可以被d整除。
而r = a - kb,两边同时除以d,r/d=a/d-kb/d=m,由等式右边可知m为整数,因此d|r
因此d也是b,a mod b的公约数
假设d是b,a mod b的公约数, 则d|b,d|(a-k*b),k是一个整数。
进而d|a.因此d也是a,b的公约数
因此(a,b)和(b,a mod b)的公约数是一样的,其最大公约数也必然相等,得证。
证法二
第一步:令c=gcd(a,b),则设a=mc,b=nc
第二步:可知r =a-kb=mc-knc=(m-kn)c
第三步:根据第二步结果可知c也是r的因数
第四步:可以断定m-kn与n互素【否则,可设m-kn=xd,n=yd,(d>1),则m=kn+xd=kyd+xd=(ky+x)d,则a=mc=(ky+x)dc,b=nc=ycd,故a与b最大公约数≥cd,而非c,与前面结论矛盾】
从而可知gcd(b,r)=c,继而gcd(a,b)=gcd(b,r),得证
注意:两种方法是有区别的。
扩展欧几里得算法
对于不完全为 0 的非负整数 a,b,gcd(a,b)表示 a,b 的最大公约数,必然
存在整数对 x,y ,使得 gcd(a,b)=ax+by。
求解 x,y的方法的理解
设 a>b。
① 显然当 b=0 时,gcd(a,b)=a。此时 x=1,y=0;
② 当 a>b>0 时,
设 ax1+ by1= gcd(a,b);
bx2+ (a mod b)y2= gcd(b,a mod b);
根据朴素的欧几里德原理有 gcd(a,b) = gcd(b,a mod b);
则:ax1+ by1= bx2+ (a mod b)y2;
即:ax1+ by1= bx2+ (a - [a / b] * b)y2=ay2+ bx2- [a / b] * by2;
说明: a-[a/b]*b即为mod运算。[a/b]代表取小于a/b的最大整数。
也就是ax1+ by1 == ay2+ b(x2- [a / b] *y2);
根据恒等定理得:x1=y2; y1=x2- [a / b] *y2;
这样我们就得到了求解 x1,y1 的方法:x1,y1 的值基于 x2,y2.
上面的思想是以递归定义的,因为 gcd 不断的递归求解一定会有个时候 b=0,所以递归可以结束。
题解题解
https://blog.csdn.net/k183000860/article/details/50211715
原来NOJ就是把POJ的P改成N再把青蛙改成美羊羊沸羊羊做出来的呀 /撑脸
附上代码:
#include <iostream>
#include <stdio.h>
using namespace std;
long long gcd(long long a,long long b,long long &x,long long &y)
{
if(b == 0)
{
x = 1;
y = 0;
return a;
}
long long r = gcd(b,a%b,x,y); //递归咋整的还是得好好理解理解
long long temp = x;
x = y;
y = temp - a/b*y;
return r;
}
int main()
{
long long x,y,m,n,l,p,q;
scanf("%lld %lld %lld %lld %lld",&x,&y,&m,&n,&l);
int r = gcd(n-m,l,p,q);
if((x-y)%r)
cout<<"Impossible";
else
{
long long d = l/r,dd = (x-y)/r;
p *= dd;
p = (p%d+d)%d;
printf("%lld\n",p);
}
return 0;
}
- NOJ 30# 分数化小数
乍一看题目是很2呢,和第一眼看“1”的传奇的感觉一样emmm
但是这里保留小数的位数是一个读入的变量呢!更何况这个变量的范围还是<=100……
我联想到在书上64页看到过手写保留小数位数的操作,就拿pow函数来试一试咯,还得结合网上找来的闻所未闻的 %g 输出(浮点数不显无意义的零"0")(woc可以把小数部分末尾的0都去掉,好NB啊)。本地运行感觉完全OK,但是贴上去是PE…ε=(´ο`*)))唉,心累
一看题解……原来用自带除法进行计算,数据的精度始终是无法达到要求的,只能自己自己手写模拟除法的过程么……怪不得呢,我就说怎么会在第30题突然来了道水题 /笑哭
附上原来的代码(后来证实最多只能保留六位小数):
#include <stdio.h>
#include <cmath>
#include <iostream>
using namespace std;
int main()
{
int a,b,c;
double ret;
cin>>a>>b>>c;
ret=(double)a/(double)b;
ret*=pow(10,c);
ret=round(ret)/pow(10,c);
printf("%g",ret);
return 0;
}
然后在找题解的过程中发现了printf的神奇用法:
printf("%*.*lf",c+1,c,(double)a/b); //输出c+1个字宽保留c位小数的浮点数运算结果
printf("%*s%s%*s",5,"","123",3,"" ); //输出5个空格,输出123,输出3个空格
printf中%后面的*号是用来表示宽度,具体的宽度由后面的变量来决定
比如
printf( “%*d”, 5,i);
和
printf( “%5d”,i);
或者
j=5;
printf( “%*d”, j, i );
是等价的
%5d的意思就是输出宽度为5的整数,如果不足5位,则在左边补空格
%-5d则是在右边补空格
%05d则是在左边补零
最后,老老实实手写除法:
#include <stdio.h>
int main()
{
int a,b,c,i;
scanf("%d %d %d",&a,&b,&c);
printf("%d.",a/b);
for (i=1; i<c; i++) {
a=(a%b)*10;
printf("%d", a/b);
}
a=(a%b)*10;
if ((a%b)*10/b >= 5) printf("%d", a/b+1);
else printf("%d", a/b);
return 0;
}
模拟竖式做除法的步骤,我迷醉了~
还有噢,最后一位要拿出来单独进行四舍五入的处理的,不能囫囵着就跟着前面一起输出了呀!
- NOJ 37# 函数模板
狗屎一般的 cin 输入
很好,你赢了,我TM记住你了,MMP!!!
- NOJ 40# 循环移位
不好意思我完全不懂
#include <iostream>
using namespace std;
unsigned rol(unsigned val, int size) //循环左移
{
unsigned res = val << size;
res |= val >> (32 - size);
return res;
}
unsigned ror(unsigned val, int size) //循环右移
{
unsigned res = val >> size;
res |= val << (32 - size);
return res;
}
int main()
{
int value,n;
cin>>value>>n;
if (n>0) cout<<ror(value,n)<<endl;
else cout<<rol(value,-n)<<endl;
return 0;
}
- NOJ 41、42# 左上角左下角右上角右下角
反对角线
if (i>=(n-j-1)) {
- NOJ 44# 选择排序
排从第s个开始的连续m个元素,应该挺基础的吧,直接上代码:
void SelectionSort(int a[],int s,int m)
{
int i,j;
for (i=s; i<s+m; i++) {
int t=i;
for (j=i+1; j<s+m; j++) {
if (a[j]>a[t]) t=j;
}
{
int temp=a[i];
a[i]=a[t];
a[t]=temp;
}
}
}
- NOJ 43# 山迪的麻烦
看到有人说是冒泡排序……好吧我来学习一下:
冒泡排序(Bubble Sort),它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。
这个算法的名字由来是因为越大的元素会经由交换慢慢“浮”到数列的顶端,所以叫“冒泡排序”。
原理
冒泡排序算法的原理如下:
比较相邻的元素。如果第一个比第二个大,就交换他们两个。
对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
#include <iostream>
using namespace std;
template<typename T>
//整数或浮点数皆可使用
void bubble_sort(T arr[], int len)
{
int i, j; T temp;
for (i = 0; i < len - 1; i++)
for (j = 0; j < len - 1 - i; j++)
if (arr[j] > arr[j + 1])
{
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
int main()
{
int arr[] = { 61, 17, 29, 22, 34, 60, 72, 21, 50, 1, 62 };
int len = (int) sizeof(arr) / sizeof(*arr);
bubble_sort(arr, len);
for (int i = 0; i < len; i++)
cout << arr[i] << ' ';
cout << endl;
float arrf[] = { 17.5, 19.1, 0.6, 1.9, 10.5, 12.4, 3.8, 19.7, 1.5, 25.4, 28.6, 4.4, 23.8, 5.4 };
len = (int) sizeof(arrf) / sizeof(*arrf);
bubble_sort(arrf, len);
for (int i = 0; i < len; i++)
cout << arrf[i] << ' ';
return 0;
}
OK啦,那题目就可以做了呢~
- NOJ 51# 字符串逆序
一边读入一边判断字符
char s[100];
while ((s[cnt]=cin.get()) != ‘ ’) {
cnt++;
}
- NOJ 53# 字符串排序
#include <string.h>
……
strcmp(a,b); //判断两字符串大小
strcpy(a,b); //将字符串b的内容复制入字符串a中
希望写个排序的函数然后在main里调用呢,没成功,貌似是因为二维数组参数传不进去?不明白呀不明白……
- NOJ 55# 字符串取整数
这题做得我一个头四个大 /托腮
主要问题是最后为啥二位数组里会被多写一遍第一行连续的整数呢?!真的好诡异啊!
最后只能开挂从后往前删掉这一行了 /摊手
好吧这个问题不管,审题才是最关键的好吗 /笑哭
“连续”表意不明呀,但是WA以后我就应该机灵一点考虑单独一个‘1’这种是不是也是题目希望我考虑进去的呀
最后用我最喜欢的暴力无脑 if 讨论法把中间重写了一遍,AC啦,完全没问题
另外请欣赏胡大佬的杰作:
#include <stdio.h>
#include <string.h>
int main(void){
char string[1024], ch;
int num[256], i = 0;
while((ch = getchar()) != '\n'){
string[i++] = ch;
}
int len = strlen(string);
int if_n = 0, count = -1, if_l = 0;
for(i = 0; i < len; i++){
if(string[i] > 47 && string[i] < 58) if_n = 1;
else if_n = 0;
if(!if_l && if_n){
//if(~count) num[count] /= 10;
num[++count] = 0;
num[count] += string[i] - 48;
}
else if(if_l && if_n){
num[count] *= 10;
num[count] += string[i] - 48;
}
else{
}
if_l = if_n;
}
printf("%d\n",++count);
for(i = 0; i < count; i++){
if(i) printf(" ");
printf("%d",num[i]);
}
return 0;
}
看来我麻里麻烦整了一个二维数组也是真TM辣鸡呢~
- NOJ 57# 字符串替换
巧做标记,输出时剔除多余空格即可
- NOJ 58# 文章统计
初试指针,真他娘的爽!!!
写了个计数函数,从函数里直接更改main里cnt的值,三个字符串分别调用三次函数就完事儿了,so easy!
- NOJ 59# Coin Test
翻了一下之前的gcd函数写了一个更相减损法求最大公约数来约分的函数gcdyf:
void gcdyf(int *a,int *b)
{
int temp_a=*a,temp_b=*b;
while (temp_a!=temp_b) {
if (temp_a>temp_b) temp_a -= temp_b;
else temp_b -= temp_a;}
int gcd=temp_b;
*a/=gcd;
*b/=gcd;
}