bupt84:Single Number

时间限制 1000 ms 内存限制 65536 KB
题目描述
Given an array with N integers where all elements appear three times except for one. Find out the one which appears only once.

输入格式
Several test cases are given, terminated by EOF.

Each test case consists of two lines. The first line gives the length of array N (1N105) , and the other line describes the N elements. All elements are ranged in [0,2631] .

输出格式
Output the answer for each test case, one per line.

输入样例

4
1 1 1 3
10
1 2 3 1 2 3 1 2 3 4

输出样例

3
4

刚看见这道题,这不是Leetcode的Single Number 2原题吗?唯一的区别是范围由int32改为int64。那就把之前在Leetcode上写的题中的循环从32改为64好了。
提交。很不幸TLE。
于是百度之,得到了下面的神算法:

#include<iostream>
#include<cstdio>
#include<map>
#include<vector>
#include<string.h>
using namespace std;
typedef long long ll;

int main()
{
    int n;ll num,c1,c2;
    while(scanf("%d",&n)!=EOF)
    {
        c1=0,c2=0;
        while(n--)
        {
            scanf("%lld",&num);
            c1=(~c2)&(c1^num);
            c2=(~c1)&(c2^num);
        }
        printf("%lld\n",c1);
    }
    return 0;
}

这个真的是很难理解啊。。。不过提交ac。
然后进行了测试,发现了下面有趣结论:
(1)scanf/printf改为cin/cout,还是TLE
(2)把ll c1,c2的变量声明放到while循环里面,TLE
(3)%lld改为%I64d,TLE(明明hdu上的标程给的全是I64d,怎么到这就不行了。。。)

那么究竟有多大差距呢?
我进行了以下实验:(windows10,编译器为MinGW64,g++ 5.3.0)
首先在E:\test\in.txt文件中随机生成 105 个长整形数,生成的文件大小为1942KB
接下来使用cin/cout读入in.txt,并写入至out.txt,源码如下:

#include<iostream>
#include<cstdio>
#include<map>
#include<vector>
#include<string.h>
using namespace std;
typedef long long ll;

int main()
{
    freopen("E:\\test\\in.txt","r",stdin);
    freopen("E:\\test\\out.txt","w",stdout);

    ll s;
    while(cin>>s)
        cout<<s<<endl;

    return 0;
}

//用时1.103秒

接下来改用scanf/printf,使用%I64d:

#include<iostream>
#include<cstdio>
#include<map>
#include<vector>
#include<string.h>
using namespace std;
typedef long long ll;

int main()
{
    freopen("E:\\test\\in.txt","r",stdin);
    freopen("E:\\test\\out.txt","w",stdout);

    ll s;
    while(scanf("%I64d",&s)!=EOF)
        printf("%I64d\n",s);

    return 0;
}

//用时0.293s

接下来用%lld:

#include<iostream>
#include<cstdio>
#include<map>
#include<vector>
#include<string.h>
using namespace std;
typedef long long ll;

int main()
{
    freopen("E:\\test\\in.txt","r",stdin);
    freopen("E:\\test\\out.txt","w",stdout);

    ll s;
    while(scanf("%lld",&s)!=EOF)
        printf("%lld\n",s);

    return 0;
}

//用时0.139s

结论:在读入大量数据时,cin/cout的速度大约是scanf %I64d的3.77倍,以及scanf %lld的7.94倍左右

那么在循环内和循环外声明变量用时差距有多大呢?
接下来的in.txt为 106 行,每行两个长整形数,out.txt为每行两个数字的和,保证不会溢出。

首先是在里面声明ll c=a+b;

#include<iostream>
#include<cstdio>
#include<map>
#include<vector>
#include<string.h>
using namespace std;
typedef long long ll;

int main()
{
    freopen("E:\\test\\in.txt","r",stdin);
    freopen("E:\\test\\out.txt","w",stdout);

    ll a,b;
    while(scanf("%lld %lld",&a,&b)!=EOF) {
        ll c=a+b;
        printf("%lld\n",c);
    }

    return 0;
}
//用时 1.856s

若改为在外面声明:

#include<iostream>
#include<cstdio>
#include<map>
#include<vector>
#include<string.h>
using namespace std;
typedef long long ll;

int main()
{
    freopen("E:\\test\\in.txt","r",stdin);
    freopen("E:\\test\\out.txt","w",stdout);

    ll a,b,c;
    while(scanf("%lld %lld",&a,&b)!=EOF) {
        c=a+b;
        printf("%lld\n",c);
    }

    return 0;
}
//用时1.662s

当然我们还可以省略c:

#include<iostream>
#include<cstdio>
#include<map>
#include<vector>
#include<string.h>
using namespace std;
typedef long long ll;

int main()
{
    freopen("E:\\test\\in.txt","r",stdin);
    freopen("E:\\test\\out.txt","w",stdout);

    ll a,b;
    while(scanf("%lld %lld",&a,&b)!=EOF) {
        printf("%lld\n",a+b);
    }

    return 0;
}
//用时1.6-1.9s不等

可见声明一个变量与使用临时变量的开销差距并不大,然而如果在很大的循环里声明变量,大约会增加10%左右的额外时间。而在acm中,时间限制是很紧张的,所以要注意这些引起无谓开销的细节。
by the way,实验二中若改用cin/cout,则耗时会高达14秒,这么高的耗时在OJ中无论如何都是不允许的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值