• 蓝桥杯之数学思维


    [4.1 奇怪的捐赠]

    地产大亨Q先生临终的遗愿是:拿出100万元给X社区的居民抽奖,以稍慰藉心中愧疚。
    麻烦的是,他有个很奇怪的要求:
    1. 100万元必须被正好分成若干份(不能剩余)。
      每份必须是7的若干次方元。
      比如:1元, 7元,49元,343元,...  
    2. 相同金额的份数不能超过5份。
    3. 在满足上述要求的情况下,分成的份数越多越好!

    请你帮忙计算一下,最多可以分为多少份?

    思路:
    代码:
    #include<cstdio>
    
    int main(){
    	
    	int n=1000*1000;
    	int re[100],a=0;
    	
    	while(n>0){
    		re[a++]=n%7;
    		n=n/7;
    	}
    	
    	int sum;
    	for(int i=0;i<a;i++){
    		sum+=re[i];
    	}
    	
    	printf("%d",sum);
    	
    }
    ------------------------------------------

    [4.2 真题:天平称重]

    用天平称重时,我们希望用尽可能少的砝码组合称出尽可能多的重量。
    如果只有5个砝码,重量分别是1,3,9,27,81
    则它们可以组合称出1到121之间任意整数重量(砝码允许放在左右两个盘中)。

    本题目要求编程实现:对用户给定的重量,给出砝码组合方案。
    例如:
    用户输入:
    5
    程序输出:
    9-3-1
    用户输入:
    19
    程序输出:
    27-9+1

    要求程序输出的组合总是大数在前小数在后。
    可以假设用户的输入的数字符合范围1~121

    [4.2 模m运算]

    思路:
    某个数由3的倍数加减来表示,可以看成某个数的三进制表示,

    代码:
    #include<cstdio>
    #include<cmath>
    
    int main(){
    	int n,a[100],k=0;
    	scanf("%d",&n);
    	
    	while(n>0){
    		int t=n%3;
    		if(t==2){
    			t=-1;
    			n=n/3+1;
    			a[k++]=t;
    			continue;
    		}
    		a[k++]=t;
    		n=n/3;
    	}
    	
    	for(int i=k-1;i>=0;i--){
    		int num=pow(3,i);
    		
    		if(i==k-1){
    			printf("%d",num);
    		}else{
    			
    			if(a[i]>0){
    				printf("+%d",num);
    			}
    			if(a[i]==0){
    				continue;
    			}
    			if(a[i]<0){
    				printf("-%d",num);
    			}			
    		}
    	}	
    }
    
    
    ------------------------------------------

    尼姆堆

    有3堆硬币,分别是3,4,5
    二人轮流取硬币。
    每人每次只能从某一堆上取任意数量。
    不能弃权。
    取到最后一枚硬币的为赢家。

    求先取硬币一方有无必胜的招法。

    数论...同余理论

    思路:

        0010
        0101
        1100
     2  1110
     --------
        0101


    x ^ y ^ x = y


    首先对所有数进行亦或,得到sum,然后将sum与每个数亦或,此时得到的数和另外所有数字亦或的结果一样,x ^ x = 0,如果这个数字比之前的数字小,就是合理的。

    代码:
    #include<cstdio>
    
    void g(int a[],int len){
    	int  sum=0;
    	for(int i=0;i<len;i++){
    		sum = sum ^ a[i];
    	}
    	
    	for(int i=0;i<len;i++){
    		int x=sum^a[i];
    		if(x<a[i]){
    			printf("%d --> %d
    ",a[i],x);
    		}
    	}
    }
    
    int main(){
    	int a[]={2,5,12,14};
    	g(a,4);
    	
    } 
    ------------------------------------------

    [4.3 因数分解]

    关键:算数基本定理

    质因数分解的唯一性

    ------------------------------------------

    求最大公约数与最小公倍数

    中国古代...辗转相除法
    欧几里得定理:gcd(a,b) = gcd(b,a%b)

    最小公倍数 = 乘积 / 最大公约数

    代码:
    #include<cstdio>
    
    int gcd(int a,int b){	
    	if(b==0) return a;
    	return gcd(b,a%b);
    }
    
    int main(){
    	int a,b,x;
    	scanf("%d%d",&a,&b); 
    	printf("gcd:%d
    ",x=gcd(a,b));	
    	printf("lcm:%d
    ",a*b/x);
    }
    ------------------------------------------

    [4.4 真题:一步之遥]

    从昏迷中醒来,小明发现自己被关在X星球的废矿车里。
    矿车停在平直的废弃的轨道上。
    他的面前是两个按钮,分别写着“F”和“B”。

    小明突然记起来,这两个按钮可以控制矿车在轨道上前进和后退。
    按F,会前进97米。按B会后退127米。
    透过昏暗的灯光,小明看到自己前方1米远正好有个监控探头。
    他必须设法使得矿车正好停在摄像头的下方,才有机会争取同伴的援助。
    或许,通过多次操作F和B可以办到。

    矿车上的动力已经不太足,黄色的警示灯在默默闪烁...
    每次进行 F 或 B 操作都会消耗一定的能量。
    小明飞快地计算,至少要多少次操作,才能把矿车准确地停在前方1米远的地方。

    请填写为了达成目标,最少需要操作的次数。

    扩展欧几里得定理:
    Ax + By = gcd(A,B) 有解

    思路:不是太明白

    代码:
    #include<cstdio>
    #include<cmath>
    
    int g(int a,int b,int arr[]){
    	
    	if(b==0){
    		arr[0]=1;
    		arr[1]=0;
    		return a;
    	}
    	
    	int ans = g(b,a%b,arr);
    	int t=arr[0];
    	arr[0]=arr[1];
    	arr[1]=t - a/b * arr[0];
    	
    	return ans;
    }
    
    
    int main(){
    	int a[2]={0};	
    	g(97,127,a);	
    	printf("%d",abs(a[0])+abs(a[1]));
    	
    }

    实用版:
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    int main(){
    	int ans[100],k=0;
    	for(int i=-1000;i<1000;i++){
    		for(int j=-1000;j<1000;j++){
    			if(97*i+127*j==1){
    				ans[k++]=abs(i)+abs(j);
    			}
    		}
    	}
    	sort(ans,ans+k);
    	printf("%d",ans[0]); 
    }
    ------------------------------------------

    [4.5 有理数运算]

    ------------------------------------------

    [4.6 作业:素数表]

    第1个素数是2,第2个素数是3,...
    求第100002(十万零二)个素数

    素数的筛法

    思路:
    使用循环,判断是否为素数,思路都非常简单,只是如果直接运算的话时间太长,我们进行优化:1、在判断素数的时候,可以将for(int i=2;i<k;i++)改为for(int i=2;i*i<=k;i++),因为一个合数至少可以分解成两个因数,其中一个因数一定小于等于它的开平方,此外,偶数一定不是素数,所以循环的时候,每步加2。

    代码:
    #include<cstdio>
    #include<cmath>
    
    int test(int k){
    	for(int i=2;i*i<=k;i++){
    		if(k%i==0){
    			return 0;
    		}
    	}
    	return 1;
    }
    
    
    int main(){
    	
    	int count=1,n=3;
    	while(count!=100002){
    		if(test(n)){
    			count++;
    		}
    		
    		n+=2;
    	}
    	
    	printf("%d",n-2);
    	
    }

  • 相关阅读:
    [linux] ubuntu gnome 控制面板恢复
    [linux] grub修改
    [erlang] 合并list
    hdu4169 Wealthy Family (树形背包)
    hdu 3899 JLUCPC
    最大流模板
    hdu 4167 User Names
    hdu 2196 Computer (树形DP)
    hdu 1011 Starship Troopers(树形DP)
    hdu 2874 Connections between cities (LCA转RMQ)
  • 原文地址:https://www.cnblogs.com/sctb/p/11919661.html
Copyright © 2020-2023  润新知