励志用尽量少的代码做高效表达
题目(提交)链接——>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、很经典的技巧题,在数据量极大时,一定采用预处理(打表)或找规律的方式解题。