周报11-21

本周练习了40道算法题。学到了很多,在这里精选几道我收获很多的题目来温故一遍。
1.洛谷p1059随机数。
输入有两行,第11行为11个正整数,表示所生成的随机数的个数NN

第22行有NN个用空格隔开的正整数,为所产生的随机数。

输出格式
输出也是两行,第11行为11个正整数MM,表示不相同的随机数的个数。

第22行为MM个用空格隔开的正整数,为从小到大排好序的不相同的随机数。

输入输出样例
输入
10
20 40 32 67 40 20 89 300 400 15
输出
8
15 20 32 40 67 89 300 40
通过这道题,我第一次接触到了查重这一概念。也学到了相对应的解决方法。
首先可以定义一个数组a[],在定义一个变量t,用于表示数组的下标。要达到查重的目的,
可以搞一个循环,每次循环都用scanf接收一个数,查重里面最重要的步骤我认为就是这一行代码:a[t] = t;就是把接受到的值存到下标为这个值的一个数组元素中,这样如果后面还接收到一样的值,就还是会把这个值存到下标为这个值的数组元素中,这样就达到了查重的目的。如果要记录不同元素的个数,那么还需加一行代码:if(a[t]!=0) ++cnt;如果这个数组元素的值不为0,就代表已经赋过值,再接收相同的值就不再进行cnt++;太妙了!代码附上:(自己提交的)

include

int main(void)
{
int n;
scanf("%d",&n);
int a[1001] = {};
int i,j,temp,t,cnt = 0;
for(i = 0;i {
scanf("%d",&t);
if(a[t]==0)
{
a[t] = t;
++cnt;
}
}
printf("%d\n",cnt);
for(i = 1;i<1001;++i)
{
if(a[i] {
temp = a[i];
for(j = i-1;a[j]>temp;–j)
{
a[j+1] = a[j];
}
a[j+1] = temp;
}
}
for(i = 1001-cnt;i<1001;++i)
{
printf("%d ",a[i]);
}
return 0;
}
2.洛谷P1482 Cantor表(升级版)
现代数学的著名证明之一是Georg Cantor证明了有理数是可枚举的。他是用下面这一张表来证明这一命题的:

1/1 1/2 1/3 1/4 1/5 …

2/1 2/2 2/3 2/4 …

3/1 3/2 3/3 …

4/1 4/2 …

5/1 …

… 这次与NOIp1999第一题不同的是:这次需输入两个分数(不一定是最简分数),算出这两个分数的积(注意该约分的要约分)后输出积在原表的第几列第几行(若积是整数或1/积,则以“积/1”或“1/积”结算)。

输入格式
共两行。每行输入一个分数(不一定是最简分数)。

输出格式
两个整数,表示输入的两个分数的积在表中的第几列第几行,注意该约分的要约分。

输入输出样例
输入
4/5
5/4
输出
1 1
通过这一题我第一次了解了约分的算法。
这一题的主要难点就是约分。可以通过以下代码实现:
gcd(a,b);
int gcd(int a,int b)
{
return b==0?a:gcd(b,a%b);
}
这里用到的是辗转相除法,我说不清,来看看欧几里得欧哥怎么说(以后忘了可以看这个复习)

欧几里得算法是用来求两个正整数最大公约数的算法。古希腊数学家欧几里得在其著作《The Elements》中最早描述了这种算法,所以被命名为欧几里得算法。
扩展欧几里得算法可用于RSA加密等领域。
假如需要求 1997 和 615 两个正整数的最大公约数,用欧几里得算法,是这样进行的:
1997 / 615 = 3 (余 152)
615 / 152 = 4(余7)
152 / 7 = 21(余5)
7 / 5 = 1 (余2)
5 / 2 = 2 (余1)
2 / 1 = 2 (余0)
至此,最大公约数为1
以除数和余数反复做除法运算,当余数为 0 时,取当前算式除数为最大公约数,所以就得出了 1997 和 615 的最大公约数
理论证明我就不写了,我记结论就行了。最后看下这一题的代码:

include

int gcd(int a,int b)
{
return b==0?a:gcd(b,a%b);
}
int main(void)
{
int a,b,x,y;
char h1,h2;
scanf("%d%c%d",&a,&h1,&b);
scanf("%d%c%d",&x,&h2,&y);
x*=a;
y*=b;
int s = gcd(x,y);
x/=s;
y/=s;
printf("%d %d\n",y,x);
return 0;
}
3.洛谷P2181 对角线
对于一个 nn 个顶点的凸多边形,它的任何三条对角线都不会交于一点。请求出图形中对角线交点的个数。
输入格式
输入只有一行一个整数 nn,代表边数。

输出格式
输出一行一个整数代表答案。

输入输出样例
输入
3
输出
0
输入
6
输出
15
这道题当时百思不得其解,但是一看题解,卧槽原来是有公式套的,学到了学到了。
看看这个公式:
n凸边形对角线交点个数=n (n-1) / 2 * (n-2) / 3 * (n-3) / 4
看下推导
首先由于不会有三条对角线交于一点,所以过某一个交点有且只能有2条对角线。

两条对角线实质上是确定了4个顶点,四个顶点构成一个四边形,所以问题就转换为求四边形的数量。

然而我们只需要确定4个顶点就得到了这个唯一确定的交点,确定一个四边形。

因此我们只需要求这样4个顶点的搭配有多少个了

也就是从n个顶点中取4个出来,即为formula(m=4)。

化简过后变为: n (n-1) (n-2) * (n-3) / 24;
卧槽,太妙了,这不记一手?
补充:n边形对角线数=
证明:n(n-3)/2
(1)n边形bai共有n个顶点,自己的不du能zhi算,相邻的不算,那么还有n-3个顶点。

(2)所以一个顶点可以dao引n-3条对角线,一共是n(n-3)条。

(3)考虑到重复的情况,所以共有n(n-3)/2条对角线。

4.P1146 硬币翻转
在桌面上有一排硬币,共NN枚,每一枚硬币均为正面朝上。现在要把所有的硬币翻转成反面朝上,规则是每次可翻转任意N-1N−1枚硬币(正面向上的被翻转为反面向上,反之亦然)。求一个最短的操作序列(将每次翻转N-1枚硬币成为一次操作)。

输入格式
一个自然数NN(NN为不大于100100的偶数)。

输出格式
第一行包含一个整数SS,表示最少需要的操作次数。接下来的SS行每行分别表示每次操作后桌上硬币的状态(一行包含NN个整数(00或11),表示每个硬币的状态:00――正面向上,和11――反面向上,不允许出现多余空格)。

对于有多种操作方案的情况,则只需操作的字典序最小输出一种。

注:操作的字典序:对于一次操作,1表示翻转,0表示不反转。

但是需要你输出的是每一次操作完的状态,0表示正面朝上,1表示反面朝上
这一题没别的,但是也是我第一次碰到逆向思维,分析过后这一题很简单,每一次都需要翻n-1枚,剩下一枚没有翻,逆着想就相当于每次只翻了一次,这样问题就简单多了,显然至少需要翻n次。

以上是这个星期让我收获最多的几道题,除此之外,通过刷算法题,让我的思维转代码的能力得到了进一步提升,每次在想问题是都会有一种很妙的感觉,顺着这种感觉,差不多就能把自己的思维用代码敲出来。这个星期还遗留了一点问题,比如说分解质因数的算法还有蛇形方阵的那一题还没能弄懂,二面题的二分法查找缺失的数也还遗留了一点问题,希望下个星期能够解决。还有,tmd修改代码的时候老是忘了给if填一个大括号,每次都要检查半天才能看出来,真NMD浪费时间,下次一定一定一定要记住,草!。突然想到链表的操作可能有点忘了,下个星期自己要敲一遍完整的。感觉这个星期的收获远不止这些,下个星期继续努力!

你可能感兴趣的:(笔记)