卡常数技巧

各种测试

i++与++i

要尽量用++i,因为i++系统会开辟空间把之前的i存下来。

#include<ctime>
#include<cstdio>

#define MAXN 100000000
#define MOD 1000000007
int Fib[MAXN+5];

int main(){
    double t1,t2;
    Fib[1]=Fib[2]=1;
    t1=clock();
    for(int i=3;i<=MAXN;i++)
        Fib[i]=Fib[i-1]+Fib[i-2];
    t2=clock();
    printf("Time of 'i++': %.4lf s\n",(t2-t1)/1000);
    for(int i=3;i<=MAXN;++i)
        Fib[i]=Fib[i-1]+Fib[i-2];
    t1=clock();
    printf("Time of '++i': %.4lf s\n",(t1-t2)/1000);
}

结果:

Time of ‘i++’: 0.5880 s
Time of ‘++i’: 0.3370 s

发现MOD没有用到,于是:

#include<ctime>
#include<cstdio>

#define MAXN 100000000
#define MOD 1000000007
int Fib[MAXN+5];

int main(){
    double t1,t2;
    Fib[1]=Fib[2]=1;
    t1=clock();
    for(int i=3;i<=MAXN;i++)
        Fib[i]=(Fib[i-1]+Fib[i-2])%MOD;
    t2=clock();
    printf("Time of 'i++': %.4lf s\n",(t2-t1)/1000);
    for(int i=3;i<=MAXN;++i)
        Fib[i]=(Fib[i-1]+Fib[i-2])%MOD;
    t1=clock();
    printf("Time of '++i': %.4lf s\n",(t1-t2)/1000);
}

结果:

Time of ‘i++’: 1.2070 s
Time of ‘++i’: 1.0520 s

END

读入优化和输出优化

这个不多说,大概千万个数据能快 200 m s 200ms 200ms,我喜欢用读入优化最主要的是可以这样写:x=read()+k,如果用scanf会多出一行。详情看这个博客:读入优化&输出优化。好像用fread可以更快,我没有试过,可以看这篇博客(也是转载的):更快的读入优化fread

神奇关键字

inline

把函数置为内联,增快调用速度。只适用于简单函数,如果复杂了,系统会自动忽略掉这些(例如AddEdge之类的可以,有递归是肯定不行的,循环似乎也不行)。
如果inline的函数里面有复杂的运算,但是是 O ( 1 ) O(1) O(1)级别的,那是最好的。

#include<ctime>
#include<cstdio>

#define MAXN 100000000
void Cal(int &x){
    x=x*(MAXN-1)%MAXN;
}
inline void inlineCal(int &x){
    x=x*(MAXN-1)%MAXN;
}

int main(){
    double t1,t2;
    int x=0;
    t1=clock();
    for(int i=1;i<=MAXN;i++)
        Cal(x);
    t2=clock();
    printf("Time of the function without 'inline': %.4lf S\n",(t2-t1)/1000);
    for(int i=1;i<=MAXN;i++)
        inlineCal(x);
    t1=clock();
    printf("Time of the function with 'inline': %.4lf S\n",(t1-t2)/1000);
}

结果:

Time of the function without ‘inline’: 1.4350 S
Time of the function with ‘inline’: 1.4170 S

话说做一亿次乘法和模运算会超过一秒……

register

变量前加上这个可以把它放在CPU寄存器里,但是太多了就不行了。
在一亿的数据下也就快了 100 m s 100ms 100ms左右。

#include<ctime>
#include<cstdio>

#define MAXN 100000000

int main(){
    double t1,t2;
    register int x=1;
    t1=clock();
    for(int i=1;i<=MAXN;i++)
        x=(x*2)%MAXN;
    t2=clock();
    printf("Time of the variables with 'register': %.4lf S\n",(t2-t1)/1000);
    int a=1;
    for(int i=1;i<=MAXN;i++)
        a=(a*2)%MAXN;
    t1=clock();
    printf("Time of the variables without 'register': %.4lf S\n",(t1-t2)/1000);
}

结果:

Time of the variables with ‘register’: 0.8290 S
Time of the variables without ‘register’: 0.9400 S

各种类型的运算速度

从测试看来,charintbool差别不大,char最快(然而可以看看例题一的玄学超时),long long瞬间变慢一半,所以对于某些一言不合就Ctrl+F全部换long long的人来说超时也很正常,double就不说了。

#include<ctime>
#include<cstdio>

#define MAXN 10000000
//开100000000运行不了,所以少了一个0
#define MOD 1000000007
int Fib1[MAXN+5];
bool Fib2[MAXN+5];
long long Fib3[MAXN+5];
char Fib4[MAXN+5];
double Fib5[MAXN+5];

int main(){
    double t1,t2;
    Fib1[1]=Fib1[2]=Fib2[1]=Fib2[2]=Fib3[1]=Fib3[2]=Fib4[1]=Fib4[2]=1;
    Fib5[1]=Fib2[2]=1;
    t1=clock();
    for(int i=3;i<=MAXN;i++)
        Fib1[i]=(Fib1[i-1]+Fib1[i-2])%MOD;
    t2=clock();
    printf("Time of 'int': %.4lf s\n",(t2-t1)/1000);
    for(int i=3;i<=MAXN;++i)
        Fib2[i]=(Fib2[i-1]+Fib2[i-2])%MOD;
    t1=clock();
    printf("Time of 'bool': %.4lf s\n",(t1-t2)/1000);
    for(int i=3;i<=MAXN;++i)
        Fib3[i]=(Fib3[i-1]+Fib3[i-2])%MOD;
    t2=clock();
    printf("Time of 'long long': %.4lf s\n",(t2-t1)/1000);
    for(int i=3;i<=MAXN;++i)
        Fib4[i]=(Fib4[i-1]+Fib4[i-2])%MOD;
    t1=clock();
    printf("Time of 'char': %.4lf s\n",(t1-t2)/1000);
    for(int i=3;i<=MAXN;++i)
        Fib5[i]=Fib5[i-1]+Fib5[i-2];
    t2=clock();
    printf("Time of 'double': %.4lf s\n",(t2-t1)/1000);
}

结果:

Time of ‘int’: 0.1280 s
Time of ‘bool’: 0.1120 s
Time of ‘long long’: 0.1770 s
Time of ‘char’: 0.1040 s
Time of ‘double’: 1.3360 s
##加 减 乘 除 模 位运算的运算速度
###加减乘除模
加减乘差不多,除法慢一点,模运算最慢(我猜是要做一遍除法和一遍减法):

#include<ctime>
#include<cstdio>

#define MAXN 100000000
#define TEST 100003

int main(){
    double t1,t2;
    int a=10000000;
    t1=clock();
    for(int i=1;i<=MAXN;i++,a=10000000)
        a=a+TEST;
    t2=clock();
    printf("'+': %.4lf\n",(t2-t1)/1000);
    for(int j=1;j<=MAXN;j++,a=10000000)
        a=a-TEST;
    t1=clock();
    printf("'-': %.4lf\n",(t1-t2)/1000);
    for(int i=1;i<=MAXN;i++,a=10000000)
        a=a/TEST;
    t2=clock();
    printf("'*': %.4lf\n",(t2-t1)/1000);
    for(int i=1;i<=MAXN;i++,a=10000000)
        a=a*TEST;
    t1=clock();
    printf("'/': %.4lf\n",(t1-t2)/1000);
    for(int i=1;i<=MAXN;i++,a=10000000)
        a=a%TEST;
    t2=clock();
    printf("'%%': %.4lf\n",(t2-t1)/1000);
}

结果:

‘+’: 0.2620
‘-’: 0.2510
‘*’: 0.2580
‘/’: 0.3460
‘%’: 0.5290
###位运算
我只测了左移和乘 2 2 2的幂,好像没有什么区别。

#include<ctime>
#include<cstdio>

#define MAXN 100000000
#define MOD 1000000007

int main(){
    double t1,t2;
    int a=10000;
    t1=clock();
    for(int i=1;i<=MAXN;i++)
        a=(a*1024)%MOD;
    t2=clock();
    printf("乘法: %.4lf\n",(t2-t1)/1000);
    for(int i=1;i<=MAXN;i++)
        a=(a<<10)%MOD;
    t1=clock();
    printf("位运算: %.4lf\n",(t1-t2)/1000);
}

英文写不下去了……
结果:

乘法: 0.9690
位运算: 0.9500

例……题

POJ-1742 Coins

https://vjudge.net/problem/POJ-1742
一份代码交HDU过,交POJ就T……
提交记录
中间的绿是用旁边大佬跟我一模一样的代码交的。

  • 加读入优化:TLE
  • 数组改到最小:TLE
  • int数组改成boolAC

最初HDU上A了,POJ上T了的代码:

#include<cstdio>
#include<cstring>

#define MAXN 220000
int N,M,L;
int A[MAXN+5],C[MAXN+5];
int W[MAXN+5],dp[MAXN+5];

int main(){
    while(1){
        scanf("%d%d",&N,&M);
        if(!N&&!M)
            break;
        for(int i=1;i<=N;i++)
            scanf("%d",&A[i]);
        for(int i=1;i<=N;i++)
            scanf("%d",&C[i]);
        L=0;
        for(int i=1;i<=N;i++){
            int k=1;
            while(2*k<=C[i]){
                W[++L]=k*A[i];
                k<<=1;
            }
            W[++L]=(C[i]-k+1)*A[i];
        }
        memset(dp,0,sizeof dp);
        dp[0]=1;
        for(int i=1;i<=L;i++)
            for(int j=M;j>=W[i];j--)
                dp[j]|=dp[j-W[i]];
        int Ans=0;
        for(int i=1;i<=M;i++)
            Ans+=dp[i];
        printf("%d\n",Ans);
    }
}

卡常A了后代码:

#include<cstdio>
#include<cstring>

inline int read(){
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}

#define MAXM 100
#define MAXN 100000
int N,M,L;
int A[MAXM+5],C[MAXM+5];
int W[MAXN+5];
bool dp[MAXN+5];

int main(){
    while(1){
        N=read(),M=read();
        if(!N&&!M)
            break;
        for(int i=1;i<=N;i++)
            A[i]=read();
        for(int i=1;i<=N;i++)
            C[i]=read();
        L=0;
        for(int i=1;i<=N;i++){
            int k=1;
            while(2*k<=C[i]){
                W[++L]=k*A[i];
                k<<=1;
            }
            W[++L]=(C[i]-k+1)*A[i];
        }
        memset(dp,0,sizeof dp);
        dp[0]=1;
        for(int i=1;i<=L;i++)
            for(int j=M;j>=W[i];j--)
                dp[j]|=dp[j-W[i]];
        int Ans=0;
        for(int i=1;i<=M;i++)
            Ans+=dp[i];
        printf("%d\n",Ans);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值