试题限制均为128MB,1Sec

总分150.

试题一

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\)。

分析

考场爆零做法

用后序遍历dfs,将子树中区间统计在子树根中,排序判断,是合法区间则上传区间两端点,不是合法区间则上传-1。

明显的bug,有可能子树不合法但当前根统计后交错一下就合法了。

#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<ctime>
#include<iostream>
#include<string>
#include<vector>
#include<list>
#include<deque>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<complex>
#pragma GCC optimize ("O0")
using namespace std;
template<class T> inline T read(T&x){
T data=0;
int w=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')
w=-1;
ch=getchar();
}
while(isdigit(ch))
data=10*data+ch-'0',ch=getchar();
return x=data*w;
}
typedef long long ll;
typedef pair<int,int> pii;
const int INF=0x7fffffff; const int MAXN=1e5+7;
int n;
struct Edge
{
int nx,to;
}E[MAXN];
int head[MAXN],ecnt;
bool noroot[MAXN]; void addedge(int x,int y)
{
E[++ecnt].to=y;
E[ecnt].nx=head[x],head[x]=ecnt;
} int ans; pii dfs(int x)
{
vector<pii>a;
for(int i=head[x];i;i=E[i].nx)
a.push_back(dfs(E[i].to));
a.push_back(pii(x,x));
sort(a.begin(),a.end());
bool valid=1;
for(int i=0;i<a.size();++i)
{
if(a[i].first==-1)
{
valid=0;
break;
}
if(i&&a[i].first!=a[i-1].second+1)
{
valid=0;
break;
}
}
if(valid)
{
++ans;
return pii(a[0].first,a[a.size()-1].second);
}
else
return pii(-1,0);
} int main()
{
freopen("A.in","r",stdin);
freopen("A.out","w",stdout);
read(n);
for(int i=1;i<n;++i)
{
int x,y;
read(x);read(y);
addedge(x,y);
noroot[y]=1;
}
int r=0;
for(int i=1;i<=n;++i)
if(!noroot[i])
{
r=i;
break;
}
dfs(r);
printf("%d\n",ans);
// fclose(stdin);
// fclose(stdout);
return 0;
}

标解

简单题,一遍dfs求出每棵子树中最小顶点编号,最大顶点编号以及子树大小即可判断该子树是否满足要求。

这种做法成立的条件是节点编号两两不同。

哈哈,T1爆零导致rank很难看。

#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<ctime>
#include<iostream>
#include<string>
#include<vector>
#include<list>
#include<deque>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<complex>
#pragma GCC optimize ("O0")
using namespace std;
template<class T> inline T read(T&x){
T data=0;
int w=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')
w=-1;
ch=getchar();
}
while(isdigit(ch))
data=10*data+ch-'0',ch=getchar();
return x=data*w;
}
typedef long long ll;
typedef pair<int,int> pii;
const int INF=0x7fffffff; const int MAXN=2e5+7;
int n;
struct Edge
{
int nx,to;
}E[MAXN];
int head[MAXN],ecnt;
bool noroot[MAXN]; void addedge(int x,int y)
{
E[++ecnt].to=y;
E[ecnt].nx=head[x],head[x]=ecnt;
} int ans;
int sz[MAXN],maxv[MAXN],minv[MAXN]; void dfs(int x)
{
sz[x]=1;
minv[x]=maxv[x]=x;
for(int i=head[x];i;i=E[i].nx)
{
int y=E[i].to;
dfs(y);
sz[x]+=sz[y];
minv[x]=min(minv[x],minv[y]);
maxv[x]=max(maxv[x],maxv[y]);
}
if(sz[x]==(maxv[x]-minv[x]+1))
++ans;
} int main()
{
freopen("A.in","r",stdin);
freopen("A.out","w",stdout);
read(n);
for(int i=1;i<n;++i)
{
int x,y;
read(x);read(y);
addedge(x,y);
noroot[y]=1;
}
int r=0;
for(int i=1;i<=n;++i)
if(!noroot[i])
{
r=i;
break;
}
dfs(r);
printf("%d\n",ans);
// fclose(stdin);
// fclose(stdout);
return 0;
}

试题二

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\)。

分析

考场做法

用\(f(i,j)\)表示前\(i\)个数满足前\(i-1\)个条件,最后一个为\(j\)的排列数个数。

拓展一下,j表示的其实是排名。

那么已经很好处理了,j确定后前i-1个数是什么就确定了,只需要前i-1个数最后一个满足条件。

  1. i-1为?,那么\(f(i,j)=\sum_{k=1}^{i-1}f(i-1,k)\)
  2. i-1为I,那么\(f(i,j)=\sum_{k=1}^{j-1}f(i-1,k)\)
  3. i-1为D,那么\(f(i,j)=\sum_{k=j}^{i-1}f(i-1,k)\)

    第三种情况为什么k从j开始呢?因为第i-1个数要比i大,而在前i-1个数中j不存在,所以j+1以后向左平移了一位。

    然后我第二维维护的树状数组,其实前缀和就行了。

    时间复杂度\(O(N^2\log N)\)
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<ctime>
#include<iostream>
#include<string>
#include<vector>
#include<list>
#include<deque>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<complex>
#pragma GCC optimize ("O0")
using namespace std;
template<class T> inline T read(T&x){
T data=0;
int w=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')
w=-1;
ch=getchar();
}
while(isdigit(ch))
data=10*data+ch-'0',ch=getchar();
return x=data*w;
}
typedef long long ll;
const int INF=0x7fffffff; const int MAXN=1e3+7,mod=1000000007;
int n;
char s[MAXN];
int f[MAXN][MAXN]; inline int lowbit(int x)
{
return x&-x;
} inline void add(int id,int p,int v)
{
while(p<=n)
{
f[id][p]+=v;
if(f[id][p]>=mod)
f[id][p]-=mod;
p+=lowbit(p);
}
} inline int query(int id,int p)
{
int res=0;
while(p)
{
res+=f[id][p];
if(res>=mod)
res-=mod;
p-=lowbit(p);
}
return res;
} int main()
{
freopen("B.in","r",stdin);
freopen("B.out","w",stdout);
scanf("%s",s+1);
n=strlen(s+1)+1;
s[0]='?';
add(0,1,1);
// cerr<<"init end"<<endl;
for(int i=1;i<=n;++i)
for(int j=1;j<=i;++j)
{
// cerr<<"procesxing "<<i<<' '<<j<<endl;
if(s[i-1]=='?')
{
add(i,j,query(i-1,n));
}
else if(s[i-1]=='D')
{
add(i,j,(query(i-1,n)+mod-query(i-1,j-1))%mod);
}
else if(s[i-1]=='I')
{
add(i,j,query(i-1,j-1));
}
}
/* for(int i=1;i<=n;++i)
for(int j=1;j<=i;++j)
{
cerr<<i<<' '<<j<<" f="<<query(i,j)-query(i,j-1)<<endl;
}*/
printf("%d\n",query(n,n));
// fclose(stdin);
// fclose(stdout);
return 0;
}

标解

用\(

test20180829的更多相关文章

随机推荐

  1. Java线程池队列吃的太饱,撑着了咋整?java 队列过大导致内存溢出

    Java的Executors框架提供的定长线程池内部默认使用LinkedBlockingQueue作为任务的容器,这个队列是没有限定大小的,可以无限向里面submit任务. 当线程池处理的太慢的时候, ...

  2. 雷林鹏分享:C# 接口(Interface)

    C# 接口(Interface) 接口定义了所有类继承接口时应遵循的语法合同.接口定义了语法合同 "是什么" 部分,派生类定义了语法合同 "怎么做" 部分. 接 ...

  3. 『cs231n』计算机视觉基础

    线性分类器损失函数明细: 『cs231n』线性分类器损失函数 最优化Optimiz部分代码: 1.随机搜索 bestloss = float('inf') # 无穷大 for num in range ...

  4. c++中的new和delete

    对于计算机程序设计而言,变量和对象在内存中的分配都是编译器在编译程序时安排好的,这带来了极大的不便,如数组必须大开小用,指针必须指向一个已经存在的变量或对象.对于不能确定需要占用多少内存的情况,动态内 ...

  5. UVA-10118 Free Candies (DP、记忆化搜索)

    题目大意:有4堆糖果,每堆有n个,有一只最多能容5个糖果的篮子.现在,要把糖果放到篮子里,如果篮子中有相同颜色的糖果,放的人就可以拿到自己的口袋.如果放的人足够聪明,问他最多能得到多少对糖果. 题目分 ...

  6. UVA-10710 Skyscraper Floors (找规律+幂取模)

    题目大意:题目中给了一种数的定义,根据定义,让判断一个给定的数是不是这种数.题中叫这种数为吉米数,定义如下:对序列1,2,3,,,,n,做n-1次SF变换(对该变换的解释在下文),如果能得到原序列,则 ...

  7. OC MRC之多对象之间管理(代码分析)

    #import <Foundation/Foundation.h> @interface Book : NSObject { int _price; } - (void)setPrice: ...

  8. 使用axios发送post请求,将JSON数据改为为form类型

    我的github(PS:希望star):https://github.com/thWinterSun/v-admin 通常前端通过POST请求向服务器端提交数据格式有4中,分别是"appli ...

  9. 如何使用Java Enum

    简单的用法:JavaEnum简单的用法一般用于代表一组常用常量,可用来代表一类相同类型的常量值.如: 性别: public enum SexEnum { male, female; } 颜色: pub ...

  10. winform窗体this方式和handle(句柄)方式的区别

    我们来比较winform窗体的this方式和win32api handle方式实现窗体的最大化.默认窗体.半透明.不透明的区别 1.窗体界面设计 this方式按钮: btnMaxWindow. btn ...