题目链接:51nod 1596搬货物
这一题把我恶心到了,连续T了6次,最后500+ms过了
先说解题思路吧,每个物品质量都是2的幂,质量和为2的幂的物体可以一起搬。假设有一个物体质量为2^x,它和另一件质量为2^y的物体能一起搬,那么也就是说存在z满足2^z =2^x+2^y,可设y = x * 2^w,z = x*2^u,也就是x * 2^u = x*1 + x*2^w,得到2^u = 1 + 2^w,这个就很明显了,w=0,u=1。也就是说两个质量一样的可以一起搬,然后两个质量为x的又可以和一个质量为2*x的一起搬,这么一来,递推式就出来了。
于是我们就可以T了(我就是这么直接写的,然后1e6的规模的O(n)复杂度,T了),就是这么诡异。想了半天也没弄懂为什么会T,最后想到了以前看到过的读入挂,在输入规模超过1e5的情况,用scanf输入就很可能T,于是就有了读入挂这玩意儿。读入挂,顾名思义给读入开挂。
我们知道C++为了兼容C语言的标准输入输出,使得cin和cout速度变得很慢,比scanf慢十倍,这时就可以用cin.tie(0)和ios::sync_with_stdio(0)来加速,这样一来就不能用scanf和printf了,具体的这里就不详细说明了,有兴趣的可以百度看看,但经过测试,这样在OJ上还是比scanf慢。于是以C++为主的ACMer习惯性的用scanf进行输入。然而,在这里要说的是读入挂,目前我知道的C语言(C++)输入最快的方式,使用getchar()读取,然后手动进行转换。下述代码中的read()就是int读入挂:
#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> #include<cmath> #define ll long long using namespace std; const int maxn = 1e6+32; int a[maxn]; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9') {ch=getchar();} while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();} return x; } int main() { int n; // freopen("51nod_Problem_1596_Test_13_In.txt", "r", stdin); // freopen("in.txt", "r", stdin); n = read(); for(int x, i = 0; i < n; ++ i) { x = read(); a[x] ++; } for(int i = 0; i < maxn; ++ i) a[i+1] += (a[i] >> 1), a[i] &= 1; int sum = 0; for(int i = 0; i < maxn; ++ i) sum += a[i]; printf("%d\n", sum); return 0; }