qbxt笔记——————dp

qbxt笔记——————dp

一:方法入门

可以用其他数更新自己,也可以用自己更新其他数

动态转移的顺序类似于DAG,先后算分明,没有环,不能任意更改

1. *斐波那契

1) for(int a=2;a<=n;a++)//被更新

{

         f[a]=f[a-1]+f[a+2];

}

2)for(int a=0,a<=n;a++)//更新别人

{

          f[a+1]+=f[a];

          f[a+2]+=f[a];

}

3)int dfs(int n)//记忆化搜索

{

        if(n==0)return 0;

        if(n==1)return 1;

        if(f[n]!=0)return f[n];

        f[n]=dfs[n-2]+dfs(n-1);

        return f[n];

}

2.* 杨辉三角组合数

int c[1001][1001];

int main()

{

       int n,m;

       cin >>n>>m;

for(int i=0;i<=n;i++)

{

        c[i][0]=1;

}

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

 for(int j=1;j<=m;j++)

{

          c[i][j]=c[i-1][j]+c[i-1][j-1];

}

cout<<c[n][m];

}

二:区间dp <o(n^3)>

合并,相邻

f[l][r]第l个到第r个合并

f[i][i]=0;f[i][i+1]=a[i]+a[i+1];

枚举断点k

f[i][j]=f[i][k]+f[k+1][j];

步骤

1 长度 2 左右端点 3 断点

1)合并石子

。。。。。。。没写

三:树形dp(喵啊)

树,最优值

f[i]:以i为根节点的树的信息

考虑目标:合并子树信息

i点的子节点个数:自己(1)+儿子的信息

用dfs

四:数位dp

*1~r个数

int sovle(int r)

{

int cnt=0;

while(r!=0)

{

      cnt++;

      z[cnt]=r%10;

       r=r/10;

}//r的数位拆完辽

memset(f,0,sinzeof(f));

f[cnt+1][1]=1;//f[i][1]:==;f[i][0]!=

for(int a=cnt;a>=1;a--)

for(int b=0;b<=1;b++)

for(int c=0;c<=9;c++)

{

        if(b==1&&c>z[a])

else

{

         if(b==0)f[a][0]+=f[a+1][b];

         else f[a][c==z[a]]+=f[a+1][b];

}

return f[1][1]+f[1][0];

}

}

*l<x<r的x的个数?

1~r的个数减1~x的个数

五:状压dp n<=22~24

用 v [ i ] [ j ] 来表示 i 状态下走到第 j 个地方的最小值。这里的 i 实质上是一个二进制数,每一位是 0 是 1 即表示每个地方有无去过,但是转为十进制表示状态,这便是状态压缩的基本思想。

1)*

f[0]=1;//啥也不选

for(int a=1;a<(1<<n);a++)

for(int b=0;b<n;b++)

if(((a>>b)&1)==0)f[a|(1<<b)]+=f[a];

//a的二进制的第b位:0可以选

//a的二进制第b位选(=1)

//从1多到1少枚举

2)*

【售货员的难题】*给n个点(xi,yi),要求所有的点走一遍,求最短欧拉距离

f[s][i]:状态为s,最后一个是i点。

六。博弈论dp

(一)

1.一个游戏g,两个人a,b

2.回合制,轮流操作

3.如果一个人没办法操作了,则ta输了

1)取石子

n个石子,a,b每次拿走至少一个石子,谁先不能拿谁输:先手必胜(全拿走了hiahiahia)

但是毒瘤的老师说这样麻烦。。。

出现了!dp!

f[i]:在剩下i个石子的时候,当前操作者必胜还是必败

f[0]=0;//f[0]必败态,因为没了

f[i]可以转移到f[i~0] ,如果你能转移到的状态中,有一个是必败态,则f[i]一定是必胜态:使对方必败

如果你能转移到的状态中,全是必胜态,则f[i]一定是必败态:使对方必胜

2)ex取石子

n个石头,a,b两个人

每次可以取3~5个石头

f[i]意义同1);

f[0、1、2]必败,f[3、4、5、6、7]必胜,f[8]必败;

*打表可知(n%8==0||n%8==1||n%8==2)时必败

(二)

两堆石头,每次从任意一堆中取走任一个,先手必败还是必胜?

不一定

n1!=n2必败

n1==n2必胜

f[i][j]:第一堆石子还有i个,第二堆还有j个时,当前操作者的必败/必胜态

(三)

k堆石子??

分成k个game,g1,g2.。。。。。。

先考虑一个,见(一):找后面有没有必败态。

定义sg[i]:对于一个必败态,定义它的sg值为0;

sg[i]=mex(可到达的状态)// 找到一个最小的没有出现过的自然数

sg[0]=0;sg[1]=1;sg[i]=i;

出现了!!!sg定理!!!

sg(g)=sg(g1)^sg(g2)^sg(g3)^.......^sg(gk)

必败态的sg值=0,sg=1为必胜态。

(代码。(三))

cin>>k;

for(int a=1;a<=k;a++)

{

        cin>>n[a];

}

sg[0]=0;

for(int i=1;a<=233333;a++)

{

          int cnt=0;

         for(int b=1;b<=a;b++)

{

          cnt++;

          z[cnt]=sg[a-b];

}

sort(z+1,z+cnt+1);

cnt=unique(z+1,z+cnt+1)-z-1;//有多少个元素

for(int b=0;;b++)

{

             if(z[b+1]!=b)

{

        sg[a]=b;

        break;

}

}

}

int ans=0;

for(int a=1;a<=n;a++)

       ans=ans^sg[n[a]];

if(ans!=0)cout<<"xianshou";

else cout<<"houshou";

位运算

|: 1010

1110 ——>0|1=1;1|1=1‘;0|0=0

1110

&: 1010

1111 ——>0&1=0;0&0=0;1&1=1

1010

^ 1010

1110 ——>0^0=1^1=0;1^0=1;

0100

<< 001010

十进制: 10

左移: 010100 ——>a<<1《==》a*2

十进制: 20

>> 001010

十进制 10

右移 000101 ——>a>>1《==》a/2

十进制 5

两维不行就三维,三维不行就四维,四维不行就五维。。。。。总有一年,你会做出来的

——长者zhx

猜你喜欢

转载自blog.csdn.net/weixin_42759798/article/details/82946085