T1 A 题
问题描述: 小 A 得到了一棵美丽的有根树。这棵树由 n 个节点以及 n - 1 条有向边构成,每条边都从父 亲节点指向儿子节点,保证除了根节点以外的每个节点都有一个唯一的父亲。树上的节点从 1 到 n 标号。该树的一棵子树的定义为某个节点以及从该节点出发能够达到的所有节点的集 合,显然这棵树共有 n 棵子树。小 A 认为一棵有根树是美丽的当且仅当这棵树内节点的标号 构成了一个连续的整数区间。现在小 A 想知道这棵树上共有多少棵美丽的子树。
输入: 第一行有一个整数 n,表示树的节点数。 接下来 n–1 行,每行两个整数 u,v,表示存在一条从 u 到 v 的有向边。 输入保证该图是一棵有根树。
输出: 输出一个整数占一行,表示对应的答案。
样例输入: 4
2 3
2 1
2 4
样例输出: 3
数据范围: 对于 20%的数据,1 ≤ n ≤ 1000。 对于 100%的数据,1 ≤ n ≤ 100000。
炒鸡大水题。由于每个节点的编号不重复且为1到n中的一个,只要记录一下子树大小还有,子树中的最大值和最小值就ok啦,如果有sz[u]==maxi[u]-mini[u]+1,则该子树符合条件,ans++即可
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#define maxn 100005
using namespace std;
int n,u,v,root,ans,num;
int deg[maxn],fir[maxn],sz[maxn],mini[maxn],maxi[maxn];
struct qwq
{
int to,nxt;
}e[maxn];
int read()
{
int xx=0,kk=1;char ch=' ';
while(!isdigit(ch)){ch=getchar();if(ch=='-')kk=-1;}
while(isdigit(ch)){xx=xx*10+ch-'0';ch=getchar();}
return kk*xx;
}
void dfs(int u)
{
sz[u]=1,mini[u]=u,maxi[u]=u;
for(int i=fir[u];i;i=e[i].nxt)
{
int v=e[i].to;
dfs(v);
sz[u]+=sz[v];
mini[u]=min(mini[v],mini[u]);
maxi[u]=max(maxi[v],maxi[u]);;
}
if(maxi[u]-mini[u]+1==sz[u]) ans++;
}
void addedge(int u,int v)
{
e[++num].to=v;
e[num].nxt=fir[u];
fir[u]=num;
}
int main()
{
freopen("A.in","r",stdin);
freopen("A.out","w",stdout);
n=read();
for(int i=1;i<n;++i)
{
u=read(),v=read();
deg[v]++,addedge(u,v);
}
for(int i=1;i<=n;++i)
if(!deg[i]) root=i;
memset(mini,127,sizeof(mini));
dfs(root);
printf("%d",ans);
return 0;
}
T2 B 题
问题描述: 对于一个排列,考虑相邻的两个元素,如果后面一个比前面一个大,表示这个位置是上升的, 用 I 表示,反之这个位置是下降的,用 D 表示。如排列 3,1,2,7,4,6,5 可以表示为 DIIDID。 现在给出一个长度为 n-1 的排列表示,问有多少种 1 到 n 的排列满足这种表示。
输入: 一个字符串 S,S 由 I,D,?组成。?表示这个位置既可以为 I,又可以为 D。
输出: 有多少种排列满足上述字符串。输出排列数模 1000000007。
样例输入: ?D
样例输出: 3
数据范围: 对于 20%的数据,S 长度 ≤ 10; 对于 100%的数据,S 长度 ≤ 1000。
动态转移的时候忘加模数啦,然后四个点炸负数,爆了60QAQ,看来还是ycy信仰不够,需要充值一波(求cymm原谅qwq)
然后说一下dp方程吧,dp[i][j]表示处理到第i个数,这个数在前i个数中排名为j的方案数。
对于 s[i]=='D'时,dp[i][j]=
s[i]=='I'时,dp[i][j]=
s[i]=='?'时,dp[i][j]=(就是前两个式子之和,代码中懒得写啦就直接用前面两个相加qwq)
然后对于求和我们可以通过前缀和来进行优化降维。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#define debug(x) cout<<#x<<" = "<<x<<endl;
#define maxn 1005
using namespace std;
const int ycy=1e9+7;
char s[maxn];
int n,u[maxn][2],d[maxn][2];
long long ans,dp[maxn][maxn];
int read()
{
int xx=0,kk=1;char ch=' ';
while(!isdigit(ch)){ch=getchar();if(ch=='-')kk=-1;}
while(isdigit(ch)){xx=xx*10+ch-'0';ch=getchar();}
return kk*xx;
}
int main()
{
freopen("B.in","r",stdin);
freopen("B.out","w",stdout);
scanf("%s",s+1);
n=strlen(s+1)+1;
dp[1][1]=1;
for(int i=2;i<=n;++i)
{
for(int j=1;j<i;++j)
dp[i-1][j]=(dp[i-1][j]+dp[i-1][j-1]+ycy)%ycy;
if(s[i-1]!='D')
for(int j=2;j<=i;++j)
dp[i][j]=dp[i-1][j-1];
if(s[i-1]!='I')
for(int j=1;j<i;++j)
dp[i][j]=(dp[i][j]+dp[i-1][i-1]-dp[i-1][j-1]+ycy)%ycy;
}
for(int i=1;i<=n;++i)
ans=(ans+dp[n][i]+ycy)%ycy;
printf("%lld",ans);
return 0;
}
T3 C 题
由于某种不可抗力很蠢地把题面题解还有代码都弄掉了QAQ,但精致的南瓜又想把自己的blog写的完完整整,就只能copy一下Achen的blog了orz
先dp出lcs,f[i][j]表示a的前i个字符和b的前j个字符的lcs.
再dp答案。g[i][j]表示a的前i个字符中长度为f[i][j]并且在b的前j个字符中出现过子序列个数。
两种转移
1、不选a[i],
如果f[i-1][j]==f[i][j]
g[i][j]+=g[i-1][j]
2、选a[i]
找到b的前j个字符中最靠后的一个和a[i]相等的字符b[k],
如果f[i-1][k-1]+1==f[i][j]
g[i][j]+=g[i-1][k-1];
//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<queue>
#include<cmath>
#include<set>
#include<map>
#define Formylove return 0
#define For(i,a,b) for(int i=(a);i<=(b);i++)
#define Rep(i,a,b) for(int i=(a);i>=(b);i--)
const int N=1007,p=1e9+7;
typedef long long LL;
typedef double db;
using namespace std;
int n,m,f[N][N];
LL g[N][N];
char a[N],b[N];
template<typename T>void read(T &x) {
char ch=getchar(); x=0; T f=1;
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') f=-1,ch=getchar();
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}
#define ANS
int main() {
#ifdef ANS
freopen("C.in","r",stdin);
freopen("C.out","w",stdout);
#endif
scanf("%s",a);
scanf("%s",b);
n=strlen(a); m=strlen(b);
For(i,0,max(n,m)) g[i][0]=g[0][i]=1;
For(i,1,n) For(j,1,m) {
if(a[i-1]==b[j-1]) f[i][j]=f[i-1][j-1]+1;
else f[i][j]=max(f[i-1][j],f[i][j-1]);
}
For(i,0,max(n,m)) g[i][0]=g[0][i]=1;
For(i,1,n) {
int k=0;
For(j,1,m) {
if(a[i-1]==b[j-1]) k=j;
if(f[i][j]==f[i-1][j]) g[i][j]=g[i-1][j];
if(k&&f[i-1][k-1]+1==f[i][j]) g[i][j]=(g[i][j]+g[i-1][k-1])%p;
}
}
printf("%lld\n",g[n][m]);
Formylove;
}