10行代码AC——UVa 10940(Throwing cards away II 数学规律+约瑟夫环)

励志用尽量少的代码做高效表达


题目(提交)链接——>UVa-10940


问题分析

本题的时间要求是3s,但极限数据量为50W*50W,一般来说,3s的时间只能支持不到三千万次的运算,也就是说,即使以O(n)为复杂度做运算,也无法满足题意。
分析到这里,我们很容易想到本题的思路是:找出规律,推公式或预处理。


预处理:
首先使用基本方法打印出前100个数字的结果: 1 2 2 4 2 4 6 8 2 4 6 8 10 12 14 16 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56 58 60 62 64 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56 58 60 62 64 66 68 70 72
规律一下就出来了。 直接用预处理的方式暴力存入数组,完成AC。

推公式:
写了几个发现规律f(n)=f(2^m+k)=2*k。



预处理代码:

#include<bits/stdc++.h>
using namespace std;
int a[500005];
int main() {
	a[1]=1;									//预处理打表,结果放入a数组。预先存入1。 
	int x = 0, i = 2;						//i为a数组的下角标,从2开始遍历 
	int flag = 1; while(flag) {
		int x1 = pow(2, x++);				//x1是循环的次数,分别等于1,2,4,8.... 
		int num = 2;						//num将赋值给a数组,分别等于2,4,6,8... 
		for(int j = 0; j < x1; j++, num+=2) {
			a[i++] = num;
			if(i >= 500001) { flag=0; break; } //break退出for循环, flag=0退出while循环 
		}
	}
	//以下为输入输出。 
	int n; while(cin>>n && n) {
		cout << a[n] << endl;
	}
return 0;}

推公式代码:

#include <bits/stdc++.h>
int main(){
    int n; while (scanf("%d",&n) != EOF && n){
        if (n == 1){ printf("1\n"); continue; }
        int cnt = 1;
        while (cnt < n)  cnt <<= 1;
        int ans = (n-cnt/2)*2;
        printf("%d\n",ans);
    }
return 0;}

总结:

1、很经典的技巧题,在数据量极大时,一定采用预处理(打表)或找规律的方式解题。

猜你喜欢

转载自blog.csdn.net/weixin_43899069/article/details/107955481