试题限制均为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. initctl 创建自己的JOB

    我们的项目需要一个启动一个外部的Jetty server.发现每次kill了这个jetty的进程后,系统会自动启动一个jetty.追查下去发现,原来是在/etc/init.d/jetty 脚本的sta ...

  2. 012 - jstat命令查看jvm的GC情况 | jvm

    jstat命令可以查看堆内存各部分的使用量,以及加载类的数量. 命令的格式如下: jstat -<option> [-t] [-h<lines>] <vmid> [ ...

  3. codeforces 578c//Weakness and Poorness// Codeforces Round #320 (Div. 1)

    题意:一个数组arr,一个数字x,要使arr-x的最大子段最小,问该最小值. 三分x,复杂度logn,内层是最大子段的模板,只能用n复杂度的.因为是绝对值最大,正负各求一次,取大的.精度卡得不得了,要 ...

  4. mysql--------四种索引类型

    一.索引的类型 mysql索引的四种类型:主键索引.唯一索引.普通索引和全文索引.通过给字段添加索引可以提高数据的读取速度,提高项目的并发能力和抗压能力.索引优化时mysql中的一种优化方式.索引的作 ...

  5. Jersey 2.x 前言和约定的文本格式

    这是Jersey 2.x 的用户指南.我们极力将它能与我们新增的功能保持一致.当阅读本指南,作为补充,也请移步至Jersey API documentation查看 Jersey 的特性和 API. ...

  6. FastDFS install - 2

    storage install nginx 1. update dependency package yum -y install pcre-devel openssl openssl-devel g ...

  7. vue 右键菜单插件 简单、可扩展、样式自定义的右键菜单

    今天分享的不是技术,今天给大家分享个插件,针对现有的vue右键菜单插件,大多数都是需要使用插件本身自定义的标签,很多地方不方便,可扩展性也很低,所以我决定写了一款自定义指令调用右键菜单(vuerigh ...

  8. httpclient 使用代理

    httpclient_使用代理 当爬取网页的时候,有的目标站点有反爬虫机制,对于频繁访问站点以及规则性访问站点的行为,会采用屏蔽IP的措施. 这时候代理IP就派上用场了. 代理的分类 透明代理 匿名代 ...

  9. flask+APScheduler 任务调度,计划任务,定时任务

    from flask import Flask from flask_apscheduler import APScheduler # 引入APScheduler from test124 impor ...

  10. GSM信道分类

    GSM是一个数字峰窝无线网络,它采用时分多址(TDMA)技术,在一个网络信道中支持多组通话.时分多址技术将一个GSM信道分为多个时隙(时间段),然后将这些时隙分配给移动电话用户,其中,分配给同一个用户 ...