F.r.a.n.k.y

dd=====(·▽·*)bლ(╹◡╹ლ)φ(≧ω≦*)♪= ̄ω ̄=φ(゜▽゜*)♪

打表的研究

打表的研究

 

一.序言:打表,又名自欺欺人算法,属于应试技巧,然而并没有任何增长水平的意义2333(但毕竟我们考试可以得分嘛==),鉴于目前考试的类型和方式,打表还是很重要的。我试图把它总结一下。

 

二.所谓定义:就是暴力写出题目中要求求的东西,并存起来,然后查询复杂度就由o(???)变成了o(1),是不是很开心2333

然后是百度百科查到的定义:

打表还可以指出租车开计价器,你要求打表(打开计价器)的话,会显示出你所经过的里程和所应支付价格,对司机而言就意味着一张发票和费用;所以问你打不打表就是问你要不要发票。如果你和司机是商谈了打车的价格,比较便宜的话,一般是不会给你打表的。正常情况下你应该坚持打表,这样如果有意外事情发生,你可以通过发票追查到你乘坐过的车辆。

啊不不不,粘错了==

打表,是一信息学专用术语,意指对一些题目,通过打表技巧获得一个有序表或常量表,来执行程序某一部分,优化时间复杂度。这种算法也可用于在对某种题目没有最优解法时,用来得到分数的一种策略。

 

三.打表步骤

1.你要先写出一个暴力程序(无视时间复杂度,你开心就好),然后把它输出的结果存到一个文件里,如果可能的话,你也可以手算(手酸);

2.把它直接粘到你程序的一个数组里;

如果数太大了怎么办呢??你可以存这个数和前一个数之差,输出前缀和,或者是直接把数掰成几瓣存(然而这样有悖打表伦理==)

而且打表的话文件可能非常大哦,但一般没关系。

 

四.打表适用范围及例子

1.读入比较水

例(HAOI2015)FROM COGS

2267. [HAOI2016]放棋子

★★★   输入文件:chess_2016.in   输出文件:chess_2016.out   简单对比
时间限制:1 s   内存限制:256 MB

【题目描述】

   给你一个你N×N的矩阵,每行有一个障碍,数据保证任意两个障碍不在同一行,任意两个障碍不在同一列,要求你在这个矩阵上放N枚棋子(障碍的位置不能放棋子),要求你放N个棋子也满足每行只有一枚棋子,每列只有一枚棋子的限制,求有多少种方案。

【输入格式】

第一行一个N,接下来一个N×N的矩阵。

【输出格式】

一个整数,即合法的方案数。

【样例输入】

2

0 1

1 0

【样例输出】

1

【数据规模】

20%的数据保证: N<=10

60%的数据保证: N<=20

100%的数据保证: N<=200

【来源】

HAOI2016

 

粘的是不是很裸==(啊不管他)

然后讲打表思路:

分析题目会发现,本题和。。。(中国:韩国3:2。。伤心)

好啦继续,本题和后面棋子的站位并无关系,!!!没错我考场上就发现了!!但是。。我并没有相信这个事实。往后推没推出来规律(听Fancy说是错排公式)。没错,要推四步的话就能推出来(然而我只推了三步(′д` )…彡…彡)

每行每列有一个障碍,所以我们发现任意交换两行或者两列对答案没有影响,不妨把障碍交换到主对角线位置,就变成了语法百题的错排问题

设f[i]表示i个人的错排方案数

f[0]=1

f[1]=0

f[i]=(f[i-1]+f[i-2])*(i-1)

考虑地i个人怎么换,一种方法是与前i-1个人里的一个互换,这是f[i-2]*(i-1),另一种是拿第j个人的,并且第j个人不拿i的,在不考虑i的情况下第j个人不拿i与第j个人不拿j是等价的,所以就是f[i-1]*(i-1)

需要高精

 

具体做法及正解请看Fancy的题解

下面说打表方面,因为读入有意义的实际上就一个n,所以你可以直接手推啊==好吧还是写暴力吧。注意需要高精哦。

 

2.部分题目有规律或给了公式

 

例:

3. 好数
(good.cpp/c/pas)
【问题描述】
我们定义一个非负整数是“好数”,当且仅当它符合以下条件之一:

1. 这个数是0或1
2. 所有小于这个数且与它互质的正整数可以排成一个等差数列
例如,8就是一个好数,因为1,3,5,7排成了等差数列。
给出N个非负整数,然后进行如下三个操作:
1. 询问区间[L,R]有多少个好数
2. 将区间[L,R]内所有数对S取余(S≤1000000)
3. 将第C个数更改为X
提示:如果你不知道如何判断一个数是否为好数,你可以打个表找找规律。
【输入格式】
输入文件名为good.in。

第一行包含两个正整数N和M,M表示操作数目
第二行包含N个非负整数。
接下来的M行每行表示1个操作:“1 L R”表示第1个操作,“2 L R S”表
示第2个操作,“3 C X”表示第3个操作。
【输出格式】
输出文件名为color.out。

对每个操作1,输出一个非负整数,表示区间内好数的个数。
【输入输出样例1】

good.in

good.out

3 6
4 6 9
1 1 3
1 3 3
2 1 1 10
1 1 3
3 2 4
1 1 3

2 0 2 2


【输入输出样例2】

good.in

good.out

8 5
12 24 17 31 16 21 18 30
1 2 5
2 4 7 7
3 2 13
1 1 8
1 3 6

3 6 4


【数据规模与约定】

样例点编号

N

M

N个数大小(≤)

具有的操作

1,2

100

100

100

1,2,3

3,4

1000

1000

1000000

1,2,3

5,6,7

100000

100000

1000000

1,3

8,9,10

100000

100000

1000000

1,2,3


这个题我不讲了2333,主要说在好数的判断上,可以直接打表啊。

3.某些题的暴力可以用打表啊。。(暴力中的n值比较小)

 把题目暴力分中的情况分类,然后暴搜。。

没错,像这样。(题就不粘了)

#include<iostream>
#include<cstdio>
using namespace std;
int n,m;
int x[300005],y[300005];
int nn[100005];
bool ans[300005];
int a;
int r[305];
int main()
{
    freopen("problem.in","r",stdin);
    freopen("problem.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x[i],&y[i]);
    }
    if(n==0||n==1)
    {
        cout<<"0";return 0;
    } 
    if(n==2)
    {
        if(m==0) 
        {
            cout<<"0";return 0;
        }
        if(m==1)
        {
            cout<<"0"<<endl<<"1";return 0;
        }
        if(m==2)
        {
            cout<<"1";return 0;
        }
    }
    if(n==3)
    {
        if(m==0) 
        {
            cout<<"0";return 0;
        }
        if(m==1)
        {
            cout<<"0"<<endl<<"1";return 0;
        }
        for(nn[1]=1;nn[1]<=3;nn[1]++)
        {
            for(nn[2]=1;nn[2]<=3;nn[2]++)
            {
                for(nn[3]=1;nn[3]<=3;nn[3]++)
                {
                    if(nn[1]!=nn[2]&&nn[1]!=nn[3]&&nn[2]!=nn[3])
                    {
                        for(int i=1;i<=m;i++)
                        {
                            if(nn[x[i]]<nn[y[i]]) r[y[i]]=1;
                        }
                        for(int i=1;i<=305;i++)
                        {
                            a=a+r[i];r[i]=0;
                        }
                        ans[a]=true;a=0;
                    }
                    
                }
            }
        }
        for(int i=0;i<=m;i++) if(ans[i]==1) printf("%d\n",i); 
        return 0;
    }
    if(n==4)
    {
        if(m==0) 
        {
            cout<<"0";return 0;
        }
        if(m==1)
        {
            cout<<"0"<<endl<<"1";return 0;
        }
        for(nn[1]=1;nn[1]<=4;nn[1]++)
            for(nn[2]=1;nn[2]<=4;nn[2]++)
                for(nn[3]=1;nn[3]<=4;nn[3]++)
                    for(nn[4]=1;nn[4]<=4;nn[4]++)
                        if(nn[1]!=nn[2]&&nn[1]!=nn[3]&&nn[1]!=nn[4]&&nn[2]!=nn[3]&&nn[2]!=nn[4]&&nn[3]!=nn[4])
                        {
                            for(int i=1;i<=m;i++)
                            {
                                if(nn[x[i]]<nn[y[i]]) r[y[i]]=1;
                            }
                            for(int i=1;i<=305;i++)
                            {
                                a=a+r[i];r[i]=0;
                            } 
                            ans[a]=true;a=0;
                        }
        for(int i=0;i<=m;i++) if(ans[i]==1) printf("%d\n",i);
        return 0;    
    }
    if(n==5)
    {
        if(m==0) 
        {
            cout<<"0";return 0;
        }
        if(m==1)
        {
            cout<<"0"<<endl<<"1";return 0;
        }
        for(nn[1]=1;nn[1]<=5;nn[1]++)
            for(nn[2]=1;nn[2]<=5;nn[2]++)
                for(nn[3]=1;nn[3]<=5;nn[3]++)
                    for(nn[4]=1;nn[4]<=5;nn[4]++)
                        for(nn[5]=1;nn[5]<=5;nn[5]++)
                        if(nn[1]!=nn[2]&&nn[1]!=nn[3]&&nn[1]!=nn[4]&&nn[1]!=nn[5]&&nn[2]!=nn[3]&&nn[2]!=nn[4]&&nn[2]!=nn[5]&&nn[4]!=nn[3]&&nn[5]!=nn[3]&&nn[5]!=nn[4])
                        {
                            for(int i=1;i<=m;i++)
                            {
                                if(nn[x[i]]<nn[y[i]]) r[y[i]]=1;
                            }
                            for(int i=1;i<=305;i++)
                            {
                                a=a+r[i];r[i]=0;
                            }
                            ans[a]=true;a=0;
                        }
        for(int i=0;i<=m;i++) if(ans[i]==1) printf("%d\n",i);
        return 0;
    }
    if(n>5)
    {
        for(int i=0;i<=n-1;i++) printf("%d\n",i);
    }
}

 

 

 

其他没什么了,毕竟是骗分,,

神犇请吐槽。2333

 

posted on 2016-09-01 21:36  Franky==  阅读(1255)  评论(0编辑  收藏  举报

导航