……DP专场引发的血案【xxx
………………今天如果是NOIP那我就退役了【x
……虽然的确是noipd考试范围内【跪地不起
T1:
题意:有根树,点有标号,求有多少棵子树上的编号是连续的一段整数
思路:记录每棵子树的size,minlable和maxlable,算一下就好了
代码:
#include<bits/stdc++.h>
#define MAXN 100005
using namespace std; int n;
vector<int> son[MAXN];
int ind[MAXN];
int cnt = 0,root;
int siz[MAXN];
int mn[MAXN],mx[MAXN];
void dfs(int now) {
mx[now] = mn[now] = now;
siz[now] = 1;
for (int i=0;i<son[now].size();++i) {
int aim = son[now][i];
dfs(aim);
siz[now] += siz[aim];
if(mx[aim] - mn[aim] + 1 == siz[aim]) ++cnt;
mx[now] = max(mx[now],mx[aim]);
mn[now] = min(mn[now],mn[aim]);
}
}
int read_x,read_y;
int main() {
freopen("A.in","r",stdin);
freopen("A.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<n;++i)
scanf("%d%d",&read_x,&read_y),son[read_x].push_back(read_y),++ind[read_y];
for (int i=1;i<=n;++i)
if(!ind[i]) {
root = i;
break;
}
dfs(root);
printf("%d",cnt+1);
return 0;
}
T2
题意:对于一个1~n的排列,可以用两个数之间的大于小于关系来表示,给出这个表示,求有多少1~n的排列满足这个表示
思路:GG
反正我先考虑的是数位dp一样的递推东西【大概是递推写多了的后遗症QAQ】……然后判去重啥的想了一年发现还是n^3的复杂度……GG
最后……发现,转移和递推式基本一样【跪地不起】,区别就是初始化那儿……
反正递推啥的就是用f[i][j]表示第i位填j的话有多少方案,然后枚举下一位填的合法的转移过去;如果没有限制每个数只出现一次显然这么搞。
然而限制了次数的话,还是想f[i][j],但是是表示填了前i位,且第i位填的是填了的数中第j大的一个。……显然转移的时候无论如何都不会重…………嗯……完事了…………至于如何让转移变成……O(1)的……前缀和后缀和啥的瞎搞搞就好了
于是感谢CYZ大爷又让我涨了姿势……这个前缀后缀和的写法我给满分【因为转移的时候系数都是1于是很显然了【
代码:
#include<bits/stdc++.h>
#define MOD 1000000007
#define MAXN 1010
using namespace std; char s[MAXN]; int n;
int f[MAXN][MAXN];
int main(){
freopen("B.in","r",stdin);
freopen("B.out","w",stdout);
scanf("%s",s);
n = strlen(s);
f[1][1] = 1;
for(int i=0;i<n;++i){
int x = i+2;
if(s[i]=='I'){
for(int j=2;j<=x;++j) f[x][j] = f[x-1][j-1];
for(int j=1;j<=x;++j) f[x][j] = (f[x][j] + f[x][j-1]) %MOD;
}
else if(s[i]=='D'){
for(int j=1;j<=x;++j) f[x][j] = f[x-1][j];
for(int j=x;j;--j) f[x][j] = (f[x][j] + f[x][j+1]) %MOD;
}
else{
int tmp = 0;
for(int j=1;j<=x;++j) (tmp += f[x-1][j]) %= MOD;
for(int j=1;j<=x;++j) f[x][j] = tmp;
}
}
int ans = 0 ;
++n;
for(int i=1;i<=n;++i) (ans += f[n][i]) %= MOD;
printf("%d",ans);
return 0;
}
T3
题意:两个字符串s1,s2,设它们的最长公共子序列的长度为L,求s1中长度为L的子序列有多少个在s2中出现过
思路:……想了想lcs怎么写啊估计要yy一会儿……先磕T2,GG
先求lcs,f[i][j]表示s1中前i个和s2中前j个的lcs长度。
…………我还是粘题解吧……反正……就这个意思23333
首先用