本质上升序列

转载题解有例子讲解很好
下面的代码中,

  • s[i] == s[j]时有两种处理方法
    • f[i]-=f[j];
    • f[j]=0;
  • s[i] > s[j]处理方法和最长上升子序列一样只不过这不是求子序列长度而是求有多少。
f[i] f[i]的值 f[i]对应的上升序列
f[0] 1 1
f[1] 2 2 12
f[2] 4 7 17 27 127
f[3] 8 8 18 28 78 128 178 278 1278
f[4] 4 13 13 23 123
f[5] 4 7 17 27 127 137 127 1237 37
按照f的定义 7 17 27 127属于f[5],因为他们的结尾都是7且都是上升序列,但是累加时这四个和f[2]对应的序列集重复 因此需要在dp[5]-dp[2]
同样也可以让f[j]==0,意味着f[i]接替并补全了f[j]的地位,在累加效果中与上方法一样。
#include <iostream>
#include <cstring>
using namespace std;
const int N = 1010;
typedef long long ll;
int f[N];
string s =
    "tocyjkdzcieoiodfpbgcncsrjbhmugdnojjddhllnofawllbhfiadgdcdjstemphmnjihecoapdjjrprrqnhgccevdarufmliqijgihhfgdcmxvicfauachlifhafpdccfseflcdgjncadfclvfmadvrnaaahahndsikzssoywakgnfjjaihtniptwoulxbaeqkqhfwl";

int main() {
	
	for (int i = 1; i < N; i++)
	{
	    f[i]=1;
	    for (int j = 0; j < i; j++) {
			if (s[i] > s[j])
				f[i] += f[j];
			else if (s[i] == s[j])
				{
				    f[i]-=f[j];
				    //f[j]=0; f[i]-=f[j]可以 f[j]=0;也可以 是不同的思路
                    
				}
		}
	}
	ll ans = 0;
	for (int i = 0; i < N; i++)
		ans += f[i];

	cout << ans << endl;
	return 0;
}
//

玩具蛇

根据题意,如果两个方案中,存在玩具蛇的某一节放在了盒子的不同格子里,则认为是不同的方案。故需在每个点都进行一次dfs,并且注意dfs的恢复现场。

#include<iostream>
#include<algorithm>
#include<cstring>


using namespace std;

const int N=10;
int g[N][N];
bool st[N][N];
int ans;//记录答案
int dx[4]={0,-1,0,1};
int dy[4]={1,0,-1,0};
void dfs(int x,int y,int index) //
{
    if(index==15)//
    {
        ans++;
        return;
    }
    st[x][y]=1;
    for(int k=0;k<4;k++)
    {
        int a=x+dx[k],b=y+dy[k];
        if(a>3||a<0||b>3||b<0)continue;
        if(st[a][b]==1)continue;
        st[a][b]=1;
        dfs(a,b,index+1); //不要是用++index作为参数 当函数回溯时 index已经加一了出现错误
        st[a][b]=0;       // 当然可以在恢复现场时候index--即可
        
    }
    return;
}
int main()
{
    for(int i=0;i<4;i++)
    {
        for(int j=0;j<4;j++)
        {
            dfs(i,j,0);
            memset(st,0,sizeof st);
        }
    }
    cout<<ans<<endl;
    return 0;
}