• acm算法模板(4)


    杂乱小模板

    状态压缩dp小技巧

    x&-x是取x的最后一个1的位置。

    x-=x&-x是去掉x的最后一个1

    读入外挂

    int nxt_int(){// neg or pos    char ch;    int flag = 0, tmp = 0;    for (ch = getchar(); ch < '0' || ch > '9'; ch = getchar())      if (ch == int('-')) break;    if (ch == int('-')) flag = 1; else tmp = int(ch) - '0';    for (ch = getchar(); '0' <= ch && ch <= '9'; ch = getchar())      tmp = tmp * 10 + int(ch) - 48;    return (flag) ? -tmp : tmp;}   

    关于N个小球放M个盒子解答

     n个球放入m个箱子里,有多少种不同的放法(不一定是球和箱子,也可能是其他的元素与其他的放置位置,例如N个人分到M个单位,每班至少一人,里面已经暗中说明球不同,单位不同) 
    看似很简单的问题其实非常复杂,球是否相同,箱是否相同?是否允许有空盒 
    不难看出一共8类情况 
    1)球同,盒同,无空箱 
    2)球同,盒同,允许空箱 
    3)球同,盒不同,无空箱 
    4)球同,盒不同,允许空箱 
    5)球不同,盒相同,无空箱 
    6)球不同,盒相同,允许空箱 
    7)球不同,盒不同,无空箱 
    6)球不同,盒不同,允许空箱 
    ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
    先来看3,4.这个就是最典型的公考中经常遇见的插板法(关于插板法的解释我懒的说了,自己搜,论坛百度都容易找的到) 
    只是需要注意是否允许空箱 
    3的公式是把n个球排成一排,(一种方法),它们中间有n-1个空。取m-1个小棍,放到空上,就把它们分成m部分,由于小棍不相邻,所以没有空箱子。它的方法数有C(N-1,M-1),也就是球减1里面挑M-1个箱子做组合 
    4的公式在3的基础上升华出来的,为了避免空箱子,先在每一个箱子假装都放一个球,这样就有n+m个球,Cn+m-1,m-1),多了M个元素而已 
    ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 
    关于1,2类情况,本来我想教大家一个特殊三角形的,但画起来比较麻烦,速度还不如穷举快,所以就略了,愿意学的我还是可以教他,不会真的还不如穷举来的快。个人建议还是用最常见的凑数法,而且公考中不会出现球和盒子数字比较大的情况。 
    法,例如7个相同球放入4个相同盒子,每盒至少一个(1号情况),则先4个盒子每个放1个,多余3个。只需要考虑这3个球的去处就OK,由于盒子相同,所以只需要凑数就OK,不必考虑位置。 
    比如300211111只有三种 
    例如7个相同球放入4个相同盒子,可以空盒,则还是凑数,大的化小的,小的化更小的。。。。。。 
    000
    001
    002
    003
    011
    012
    013
    022
    111
    112
    122
    11 
    1234公考常见类型,必须学会!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
    -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
    1234都是球相同的情况。但如果球不同怎么办??? 
    先来分析最特殊的8号:N球不同,M箱不同,允许空。每个球都有M种选择,N个球就有MN次方分法。 
    关于567这情况,自己推咯,
    看起来很复杂,其实很简单 
    第一左右两边都是1,第几行就有几个数,比如第5行就是1XXX1 
    2 Sn,k)=S(n-1,k-1)+k*S(n-1,k),含义是第N排的第K个数等于他上一排的上一个位置数字加上一排的同样位置数字的K 
    例如S73)就是第7排第3个数字,所以他等于上排第6排第2个数字+6排第3个位置*3 
    所以画图的话,明显第1排是1,第211,推理第3排(左右两边都是1,只有中间那个数字没确定) 
    所以S(3,2)=2排第1个数字+2排第2个数字两倍=1+1*2=3,所以第3排数字就是1,3,1.同理S(4,2)=S(3,1)+2*S(3,2)=1+2*3=7, 
    S(4,3)=S(3,2)+3*S(3,3)=3+3*1=6......如此类推三角形 
    ----------------------------------------------------------------------------------------- 
    当遇见类型5即:N不同球,M同箱子,无空箱。一共有S(N,M)种分法,比如7个不同球,4个相同箱子,每个箱子至少一个,则看三角形的第7行,第4个数字多少。 
    而类型6N不同球,M同箱,允许空的时候(在类型5的基础上允许空箱)。明显是N个球不变,一个空箱子都没有+有一个空箱子+有两个空箱子+有三个空箱子+,,,,,,都装在一个箱子。说的简单点一共有就是 
    S(N,1)+S(N,2)+S(N,3)+..........S(N,M)=也就是说第N排开始第1个数字一直加到第M个数字就是总的分法 
    ---------------------------------------------------------------------------------------- 
    而类型7同样是在类型5的基础上升华,因为5是箱同的,而7箱不同,所以箱子自身多了P(M,M)=M!倍可能 
    所以类型7的公式就是M!乘以S(N,M) 

    /***************************筛法打素数表*************************/

    /*

    **函数作用是打不超过n的所有素数

    **注意n不能超过上限  会数组越界和超时

    **返回值是素数表中素数个数  _prime储存素数

    **_prime一定是数组的指针

    */

    int print_prime(int n,int *_prime)

    {

    bool sign[200000];

    memset(sign,0,sizeof(sign));

    sign[1]=true;//对于认为1是素数的题我们可以把这句话注释掉

    int i,j,k;

    for(i=4;i<=n;i+=2)

    sign[i]=true;

    for(i=3;i<=n;i+=2)

    {

    if(!sign[i])

    {

    k=2*i;

    for(j=i*i;j<=n;j+=k)

    sign[j]=true;

    }

    }

    memset(_prime,0,sizeof(_prime));

    int num=0;

    for(i=1;i<=n;i++)

    if(!sign[i])

    _prime[num++]=i;

    return num;

    }

    二分求幂

    /*

    **二分求幂的函数  注意long long有时候要用__int64

    **传值的时候可以强制性转换

    */

    long long half_n(long long x,long long n,long long mod)

    {

    if(x==0)

    return 0;

    if(x==1||n==0)

    return 1;

    long long temp,ans;

    temp=x;

    ans=1;

    while(n)

    {

    if(n&1)

    ans=ans*temp%mod;

    temp=temp*temp%mod;

    n=n>>1;

    }

    return ans;

    }

    判断是不是质数

    bool is_prime(int x)

    {

    int i;

    if(x>2&&x%2==0)

    return false;

    for(i=3;i*i<x;i+=2)

    if(x%i==0)

    return false;

    return true;

    }

    /***********************最大公约数和最小公倍数********************/

    long long gcd(long long a,long long b)

    {

    long long temp;

    while(b)

    {

    temp=b;

    b=a%b;

    a=temp;

    }

    return a;

    }

    long long lcm(long long a,long long b)

    {

    return a /gcd(a,b) *b;

    }

     

    /*********************格式化输入输出*********************************/

    符号 作用

      —————————————————————————— 

      %d 十进制有符号整数 

      %u 十进制无符号整数 

      %f 浮点数 

      %s 字符串 

      %c 单个字符 

      %p 指针的值 

      %e 指数形式的浮点数 

      %x, %X 无符号以十六进制表示的整数 

      %o 无符号以八进制表示的整数 

      %g 自动选择合适的表示法 

      ━━━━━━━━━━━━━━━━━━━━━━━━━━ 

      说明

      (1). 可以在"%"和字母之间插进数字表示最大场宽。 

      例如: %3d 表示输出3位整型数不够3位右对齐。 

      %9.2f 表示输出场宽为9的浮点数其中小数位为2, 整数位为6, 

      小数点占一位不够9位右对齐。 

      %8s 表示输出8个字符的字符串不够8个字符右对齐。 

      如果字符串的长度、或整型数位数超过说明的场宽将按其实际长度输出。 

      但对浮点数若整数部分位数超过了说明的整数位宽度将按实际整数位输出

      若小数部分位数超过了说明的小数位宽度则按说明的宽度以四舍五入输出。 

      另外若想在输出值前加一些0, 就应在场宽项前加个0。 

      例如: %04d 表示在输出一个小于4位的数值时将在前面补0使其总宽度 

      为4位。 

      如果用浮点数表示字符或整型量的输出格式小数点后的数字代表最大宽度

      小数点前的数字代表最小宽度。 

      例如: %6.9s 表示显示一个长度不小于6且不大于9的字符串。若大于9, 则 

      第9个字符以后的内容将被删除。 

      (2). 可以在"%"和字母之间加小写字母l, 表示输出的是长型数。 

      例如: %ld 表示输出long整数 

      %lf 表示输出double浮点数 

      (3). 可以控制输出左对齐或右对齐即在"%"和字母之间加入一个"-" 号可 

      说明输出为左对齐否则为右对齐。 

      例如: %-7d 表示输出7位整数左对齐 

      %-10s 表示输出10个字符左对齐 

      2. 一些特殊规定字符 

    ━━━━━━━━━━━━━━━━━━━━━━━━━━

     

    /*************************立方之和和******************************/

    1^3+2^3+.....+n^3=n^2(n+1)^2/4=[n(n+1)/2]^2

    /****************************平方之和***************************************/

    1/6*n*(n+1)*(2*n+1);

    /*****************************k次方之和********************************/

     

     

     

     

    /**************************完全数*******************************-/

     

     1……6 

      2……28 

      3……496 

      4……8128 

      5……33550336 

      6……8589869056 

      7……137438691328 

      8……2305843008139952128 

      9……2658455991569831744654692615953842176 

      10……191561942608236107294793378084303638130997321548169216 

    11……13164036458569648337239753460458722910223472318386943117783728128 

    12……14474011154664524427946373126085988481573677491474835889066354349131199152128

    /**************************************////////////

    /*******************//////////////////////////////

    /********************梅森素数****************************/

    n

    Mn

    Mn的位数

    1

    2

    3

    1

    2

    3

    7

    1

    3

    5

    31

    2

    4

    7

    127

    3

    5

    13

    8191

    4

    6

    17

    131071

    6

    7

    19

    524287

    6

    8

    31

    2147483647

    10

    9

    61

    2305843009213693951

    19

    10

    89

    618970019…449562111

    27

    11

    107

    162259276…010288127

    33

    12

    127

    170141183…884105727

    39

    13

    521

    686479766…115057151

    157

    14

    607

    531137992…031728127

    183

    15

    1,279

    104079321…168729087

    386

    16

    2,203

    147597991…697771007

    664

    17

    2,281

    446087557…132836351

    687

    18

    3,217

    259117086…909315071

    969

    19

    4,253

    190797007…350484991

    1,281

    20

    4,423

    285542542…608580607

    1,332

    21

    9,689

    478220278…225754111

    2,917

    22

    9,941

    346088282…789463551

    2,993

    23

    11,213

    281411201…696392191

    3,376

    24

    19,937

    431542479…968041471

    6,002

    25

    21,701

    448679166…511882751

    6,533

    26

    23,209

    402874115…779264511

    6,987

    27

    44,497

    854509824…011228671

    13,395

    28

    86,243

    536927995…433438207

    25,962

    29

    110,503

    521928313…465515007

    33,265

    30

    132,049

    512740276…730061311

    39,751

    31

    216,091

    746093103…815528447

    65,050

    32

    756,839

    174135906…544677887

    227,832

    33

    859,433

    129498125…500142591

    258,716

    34

    1,257,787

    412245773…089366527

    378,632

    35

    1,398,269

    814717564…451315711

    420,921

    36

    2,976,221

    623340076…729201151

    895,932

    37

    3,021,377

    127411683…024694271

    909,526

    38

    6,972,593

    437075744…924193791

    2,098,960

    39

    13,466,917

    924947738…256259071

    4,053,946

    40*

    20,996,011

    125976895…855682047

    6,320,430

    41*

    24,036,583

    299410429…733969407

    7,235,733

    42*

    25,964,951

    122164630…577077247

    7,816,230

    43*

    30,402,457

    315416475…652943871

    9,152,052

    44*

    32,582,657

    124575026…053967871

    9,808,358

    45*

    37,156,667

    202254406…308220927

    11,185,272

    46*

    42,643,801

    169873516…562314751

    12,837,064

    47*

    43,112,609

    316470269…697152511

    12,978,189

    /*****************************KMP***********************************/

    void getnext(char str[],int next[])

    {

    int len=strlen(str);

    int i=0;next[i]=-1;

    int j=-1;

    while(i<len)

    {

    if(j==-1||str[i]==str[j])

    {

    i++;j++;

    next[i]=j;

    }

    else

    j=next[j];

    }

    }

    int KMP(char str1[],char str2[],int pos,int next[])

    {

    int len1=strlen(str1);

    int len2=strlen(str2);

    int i,j;

    i=pos;j=0;

    while(i<len1&&j<len2)

    {

    if(j==-1||str1[i]==str2[j])

    {

    i++;j++;

    }

    else

    j=next[j];

    }

    if(j==len2)

    return i-len2;

    return -1;

    }

    /////////////////////树状数组///////////////////

    Code

    int lowbit(int x)//计算lowbit

    {

        return x&(-x);

    }

    void add(int i,int val)//将第i个元素更改为val

    {

        while(i<=n)

        {

            c[i]+=val;

            i+=lowbit(i);

        }

    }

    int sum(int i)//求前i项和

    {

        int s=0;

        while(i>0)

        {

            s+=c[i];

            i-=lowbit(i);

        }

        return s;

    }

    /***************** 关于分割平面的探讨************************/

    1.直线(Line)分割平面

     

    由于第n条直线与前n-1条直线相交于n-1个点,这n-1个点将第n条直线划分为n个部分,而这第n条直线的两边分别有L(n-1)n个部分。故L(n)=L(n-1)+n L(0) = 1

     

    2.一次折线(Zig)分割平面

     

    由于一条一次折线相对于两条直线相交少了两个部分,所以Z(n) = L(2n) - 2n Z(0) = 2

     

    3.Z型折线(Zig-zag)分割平面

     

    Z型线与三条之间很相似,但是有两条平行,这样就少了1个部分,如果再将有两条直线平行的三条直线变为Z型的话,则又将少4个部分,这样每个Z型折线比三条直线分平面形成的部分少5个。故ZZ(n) = L(3n)-5n

     

    P.S.对于2,3而言由于后面的图形与前面的图形相交时要获得尽量多的区间,所以交点不会在顶点处,既然不在顶点处,那么本来这个图形相比直线而言少了几个区间,与其他图形相交后仍然少那几个区间

     

    4.(Circle)相交

     

    n个圆与前n-1个圆相交于2(n-1)个点,这2(n-1)个点将第n个圆划分为2(n-1)个圆弧,这每条弧都将原来的一个旧区域一分为二。故C(n) = C(n-1) + 2(n-1) C(0) = 1

     

    5.平面(Flat)分割空间

     

    n个平面与前n-1个平面有n-1条交线,这n-1条交线分割第n个平面为L(n-1)个区域,则在这个平面的两侧分别把空间分为F(n-1)L(n-1)个区域,故F(n) = F(n-1) + L(n-1)

     

    6.对没有三条对角线交于一点的凸多边形,计算各边和对角线组成的互不重叠的区域个数

     

        我们从各区域的顶点总数和所有区域的内角和的总和两个角度进行分析:

     

        设:Nk为区域中k边形的个数。

     

        角度1:各区域顶点总数(包括重复计算的数目)的等式为

     

                     3N3 + 4N4 + ... + mNm = 4C(n,4) + n(n-2)                                          (等式1)

     

                     其中m是各区域边数的最大值,n是凸多边形的顶点数。

     

                      左式表示的各区域顶点总数来自两个方面:

     

                      由于每两条对角线(或四个顶点)决定一个内部区域的顶点,因此区域的顶点数是4C(n,4),即每个内部顶点在左式中计数4(总是四个区域公共一个顶点).又因为在计算中,凸多边形的每个顶点(n-2个三角型的公共顶点)重复计数n-2,因此左式的计算中,n个顶点被计数为n(n-2).

     

        角度2:所有区域的内角和的总和的等式为

     

                     180N1 + 360N2 + 540N3 + ... + (m-2)180Nm = C(n,4)360 + (n-2)180   (等式2)

     

                    左式表示的所有区域的内角和的总和来自两个方面:

     

                    (1)各内部顶点处区域内角和(360)的总和为C(n,4)360

     

                    (2)凸多边形的内角和为(n-2)180

     

                    等式2两边同时除以180,得出

     

                    N3 + 2N4 + ... + (m-2)Nm = 2C(n,4) + (n-2)                                           (等式3)

     

                    殊途同归,由等式1两边同时减去等式3两边,可得出区域总数:

     

                    N3 + N4 + N4 + ... Nm = C(n,4) + C(n-1,2)

     

    这就是说,所求的区域总数为C(n,4) + C(n-1,2)

     

    7.n条直线划分矩形

     

        每条直线和矩形必然交于两点,这两点任一个都必然同时属于两个多边形.矩形内部n条直线两两相交且没有3条交于同一点,所以产生n(n-1)/2个交点,每个交点属于4个多边形,所以矩形边上和内部的点数一共为 n(n-1)/2+2n=n(n+3)/2.如果尽量让直线与矩形相交的时候交点不是矩形的顶点的话还会多出来4个顶点,每个顶点只属于一个多边形,所以总的点数为n(n+3)/2+4 = (n^2+3n+8)/2.

     

        内部每个交点处内角和为360,边上每个交点内角和为180,顶点处内角和为90,4个加起来是360,仿照5的方法列方程可得到区域总数为(n^2+n+2)/2

     

    8.圆圈上n个点两两连线最多把圆分成多少个区域

     

        先把每个点和与它相邻的两个点相连,这样就转化成凸多边形的问题了,求出凸多边形内部的区域数,再加上n就行了.

     

    /***********************************************************************/

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

  • 相关阅读:
    Echarts框架的使用
    变身windows达人,用运行命令直接启动所有应用程序
    Google为何这么屌
    骗子利用淘宝支付宝退款欺诈
    卡常技巧
    C++set用法
    分块大法好
    高精度乘法
    phpstudy初谈(基础教程)
    读入,输出优化
  • 原文地址:https://www.cnblogs.com/jeff-wgc/p/4484680.html
Copyright © 2020-2023  润新知