NOIP#17模拟赛
共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.1
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。
tarjn加dfs。
因为tarjin中的
col[stack[top]]=sumcol;写成了
col[stack[top]]=now;
挂了一半的点,要注意!!!!!!!!
#include<map> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define MAXN 100001 using namespace std; map<int,int>ma[MAXN]; int n,m; int tot,tot1; int tim,top,sumcol; int col[MAXN],dis[MAXN]; int ans[MAXN],into[MAXN],vis[MAXN]; int to[MAXN],net[MAXN],head[MAXN]; int to1[MAXN],net1[MAXN],head1[MAXN]; int low[MAXN],dfn[MAXN],stack[MAXN],visstack[MAXN]; void add(int u,int v){ to[++tot]=v;net[tot]=head[u];head[u]=tot; } void add1(int u,int v){ to1[++tot1]=v;net1[tot1]=head1[u];head1[u]=tot1; } int tarjin(int now){ low[now]=dfn[now]=++tim; stack[++top]=now; vis[now]=1; visstack[now]=1; for(int i=head[now];i;i=net[i]) if(visstack[to[i]]) low[now]=min(low[now],dfn[to[i]]); else if(!vis[to[i]]){ tarjin(to[i]); low[now]=min(low[now],low[to[i]]); } if(dfn[now]==low[now]){ sumcol++; col[now]=sumcol; while(stack[top]!=now){ col[stack[top]]=sumcol; visstack[stack[top]]=0; top--; } visstack[now]=0; top--; } } void dfs(int now){ for(int i=head1[now];i;i=net1[i]){ dfs(to1[i]); dis[now]=max(dis[now],dis[to1[i]]); } } int main(){ freopen("graph.in","r",stdin); freopen("graph.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ int u,v; scanf("%d%d",&u,&v); add(u,v); } for(int i=1;i<=n;i++) if(!vis[i]) tarjin(i); for(int i=1;i<=n;i++) for(int j=head[i];j;j=net[j]) if(col[i]!=col[to[j]]) if(ma[col[i]].find(col[to[j]])==ma[col[i]].end()){ ma[col[i]][col[to[j]]]=1; add1(col[i],col[to[j]]); into[col[to[j]]]++; } for(int i=1;i<=n;i++) dis[col[i]]=max(dis[col[i]],i); for(int i=1;i<=sumcol;i++) if(!into[i]) dfs(i); for(int i=1;i<=n;i++) cout<<dis[col[i]]<<" "; fclose(stdin); fclose(stdout); return 0; }
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
数组开小了,gg,找一个最长严格上升子序列。
#include<cstdio> #include<iostream> using namespace std; const int maxn=100005; const int oo=0x3fffffff;//极大值 int a[maxn]; int lis[maxn], pos[maxn]; int main(){ int n; cin>>n; for(int i=1;i<=n;i++) scanf("%d",a+i); int top=0; lis[0]=-oo; for(int i=1;i<=n;i++){ if(a[i]>lis[top]&&a[i]-lis[top]-1>=i-pos[top]-1){ lis[++top]=a[i]; pos[top]=i; } else{ int l=0, r=top, tp=-1; while(l<=r){ int mid=(l+r)>>1; if(a[i]-lis[mid]-1>=i-pos[mid]-1){ tp=mid; l=mid+1; } else r=mid-1; } if(tp!=-1) lis[tp+1]=a[i], pos[tp+1]=i; } } cout<<n-top<<endl; } return 0; }
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
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define MAXN 1001 using namespace std; int n,k; int c1[MAXN],c2[MAXN]; struct nond{ int num[1000]; }f[101][101]; void mul1(int lena1,int q,int aa,int bb){ memset(c1,0,sizeof(c1)); for(int i=0;i<=lena1;i++) c1[i]=f[aa-1][bb-1].num[i]; for(int i=1;i<=lena1;i++) c1[i]*=q; for(int i=1;i<=lena1;i++){ if(c1[i]>=10){ if(i==lena1) lena1++; c1[i+1]+=c1[i]/10; c1[i]%=10; } } for(;lena1>=1;lena1--) if(c1[lena1]!=0) break; c1[0]=lena1; } void mul2(int lena2,int q,int aa,int bb){ memset(c2,0,sizeof(c2)); for(int i=0;i<=lena2;i++) c2[i]=f[aa-1][bb].num[i]; for(int i=1;i<=lena2;i++) c2[i]*=q; for(int i=1;i<=lena2;i++){ if(c2[i]>=10){ if(i==lena2) lena2++; c2[i+1]+=c2[i]/10; c2[i]%=10; } } for(;lena2>=1;lena2--) if(c2[lena2]!=0) break; c2[0]=lena2; } void jia(int aa,int bb){ c1[0]=max(c1[0],c2[0]); for(int i=1;i<=c1[0];i++) c1[i]+=c2[i]; for(int i=1;i<=c1[0];i++) if(c1[i]>=10){ if(i==c1[0]) c1[0]++; c1[i+1]+=c1[i]/10; c1[i]%=10; } for(;c1[0]>=1;c1[0]--) if(c1[0]!=0) break; for(int i=0;i<=c1[0];i++) f[aa][bb].num[i]=c1[i]; } int main(){ freopen("permutation.in","r",stdin); freopen("permutation.out","w",stdout); scanf("%d%d",&n,&k); f[1][0].num[1]=1;f[1][0].num[0]=1; f[2][0].num[1]=1;f[2][0].num[0]=1; f[2][1].num[1]=1;f[2][1].num[0]=1; for(int i=3;i<=n;i++) f[i][0].num[0]=1,f[i][0].num[1]=1; for(int i=3;i<=n;i++) for(int j=1;j<i;j++){ int k=i-j,tot1=0; int kk=j+1,tot2=0; mul1(f[i-1][j-1].num[0],k,i,j); mul2(f[i-1][j].num[0],kk,i,j); jia(i,j); } for(int i=f[n][k].num[0];i>=1;i--) cout<<f[n][k].num[i]; } /* 20 15 */