20170613NOIP模拟赛
共3道题目,时间3小时
题目非原创,仅限校内交流使用
题目名称 |
Graph |
Incr |
Permutation |
文件名 |
graph |
incr |
permutation |
输入文件 |
graph.in |
incr.in |
permutation.in |
输出文件 |
graph.out |
incr.out |
permutation.out |
时间限制 |
1000ms |
1000ms |
1000ms |
内存限制 |
256mb |
256mb |
256mb |
测试点数目 |
10 |
10 |
10 |
测试点分值 |
10 |
10 |
10 |
是否有部分分 |
否 |
否 |
否 |
题目类型 |
传统 |
传统 |
传统 |
评测环境
操作系统:Windows XP Professional SP3
CPU: Intel(R) Pentium(R) CPU G2030 @ 3.00GHz (2CPUs)
系统内存:2GB
评测工具:Cena 0.8.
Problem 1 Graph (graph.cpp/c/pas)
【题目描述】
给出 N 个点,M 条边的有向图,对于每个点 v,求 A(v) 表示从点 v 出发,能到达的编号最大的点。
【输入格式】
第 1 行,2 个整数 N,M。 接下来 M 行,每行 2 个整数 Ui,Vi,表示边 ⟨Ui,Vi⟩。点用 1,2,...,N 编号。
【输出格式】
N 个整数 A(1),A(2),...,A(N)。
【样例输入】
4 3
1 2
2 4
4 3
【样例输出】
4 4 3 4
【数据范围】
对于 60% 的数据,1 ≤ N,K ≤ 10^3;
对于 100% 的数据,1 ≤ N,M ≤ 10^5。
思路
dfs/Tarjan/拓扑序列/bfs皆可。
Problem 2 Incr(incr.cpp/c/pas)
【题目描述】
数列 A1,A2,...,AN,修改最少的数字,使得数列严格单调递增。
【输入格式】
第 1 行,1 个整数 N
第 2 行,N 个整数 A1,A2,...,AN
【输出格式】
1 个整数,表示最少修改的数字
【样例输入】
3
1 3 2
【样例输出】
1
【数据范围】
对于 50% 的数据,N ≤ 10^3
对于 100% 的数据,1 ≤ N ≤ 10^5,1 ≤ Ai ≤ 10^9
思路
对于每个Ai,先减去i,然后求最长严格上升子序列a;
ans=n-a;
代码实现
1 #include<cstdio> 2 const int maxn=1e5+10; 3 int n,a; 4 int s[maxn],v[maxn]; 5 int main(){ 6 scanf("%d",&n); 7 for(int i=1;i<=n;i++) scanf("%d",&s[i]),s[i]-=i; 8 v[++a]=s[1]; 9 for(int i=1;i<=n;i++){ 10 if(v[a]<s[i+1]) v[++a]=s[i+1]; 11 else 12 for(int j=1;j<=a;j++) 13 if(s[i+1]<v[j]){v[j]=s[i+1];break;} 14 } 15 printf("%d",n-a); 16 return 0; 17 }
Problem 3 Permutation (permutation.cpp/c/pas)
【题目描述】
将 1 到 N 任意排列,然后在排列的每两个数之间根据他们的大小关系插入“>”和“<”。
问在所有排列中,有多少个排列恰好有K个“<”。
例如排列(3, 4, 1, 5, 2)
3 < 4 > 1 < 5 > 2
共有2个“<”
【输入格式】
N,K
【输出格式】
答案
【样例输入】
5 2
【样例输出】
66
【数据范围】
20%:N <= 10
50%:答案在0..2^63-1内
100%:K < N <= 100
思路
DP方程:f[i][j]=f[i-1][j]*(j+1)+f[i-1][j-1]*(i-j);
代码实现
1 #include<cstdio> 2 const int maxn=110; 3 inline int max_(int x,int y){return x>y?x:y;} 4 int n,k; 5 int s[2][110][300]; 6 void tot(int i,int j,int v1,int v2){ 7 int b=max_(s[i^1][j][0],s[i^1][j-1][0]); 8 for(int a=1;a<=b;a++) s[i][j][a]=s[i^1][j][a]*v1+s[i^1][j-1][a]*v2; 9 for(int a=1;a<=b;a++) 10 if(s[i][j][a]>999){ 11 s[i][j][a+1]+=s[i][j][a]/1000; 12 s[i][j][a]%=1000; 13 if(a==b) b++; 14 } 15 s[i][j][0]=b; 16 } 17 void put(int i,int j){ 18 printf("%d",s[i][j][s[i][j][0]]); 19 for(int a=s[i][j][0]-1;a>0;a--) 20 printf("%03d",s[i][j][a]); 21 } 22 int main(){ 23 freopen("permutation.in","r",stdin); 24 freopen("permutation.out","w",stdout); 25 scanf("%d%d",&n,&k); 26 s[0][0][0]=s[0][0][1]=s[1][0][0]=s[1][0][1]=1; 27 for(int i=1;i<=n;i++) 28 for(int j=1;j<=k;j++) 29 tot(i&1,j,j+1,i-j); 30 put(n&1,k); 31 return 0; 32 }