zoukankan      html  css  js  c++  java
  • 2014-10-30NOIP复习题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。

    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

    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


    NOIP复习题旨在复习知识点,故写详细一点啦

    T1:

    强联通分量缩点的裸题(我当时竟然以为第一题应该不会太难而没考虑环,结果40分炸掉QAQ)

    我用的是Kosaraj+dfs缩点,效率很低

    不过还是写一下吧,反正我不会tarjan~

    先是两遍深搜获取基本信息,然后再一遍深搜把各个缩点连接起来

    最后一遍拓扑排序。

    总共四边搜索,四次清空bool数组,三个邻接表

    程序太垃圾啦~

      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<algorithm>
      4 #include<cstring>
      5 #include<vector>
      6 #define MAXN 100005
      7 using namespace std;
      8 vector<int> G[MAXN];
      9 vector<int> rG[MAXN];
     10 vector<int> nG[MAXN];
     11 vector<int> vs;
     12 int cmp[MAXN],cnt;
     13 int m[MAXN];
     14 int b[MAXN];
     15 int ru[MAXN];
     16 int V,E;
     17 void dfs1(int x){
     18     b[x]=1;
     19     for(int i=0;i<G[x].size();i++){
     20         int y=G[x][i];
     21         if(!b[y]){
     22             dfs1(y);
     23         }
     24     }
     25     vs.push_back(x);
     26 }
     27 void dfs2(int x){
     28     b[x]=1;
     29     cmp[x]=cnt;
     30     m[cnt]=max(m[cnt],x);
     31     for(int i=0;i<rG[x].size();i++){
     32         int y=rG[x][i];
     33         if(!b[y]){
     34             dfs2(y);
     35         }
     36     }
     37 }
     38 void suo(int x){
     39     b[x]=1;
     40     for(int i=0;i<G[x].size();i++){
     41         int y=G[x][i];
     42         if(cmp[x]!=cmp[y]){
     43             nG[cmp[x]].push_back(cmp[y]);
     44             ru[cmp[y]]++;
     45         }
     46         if(!b[y]){
     47             suo(y);
     48         }
     49     }
     50 }
     51 void topoSort(int x){
     52     b[x]=1;
     53     for(int i=0;i<nG[x].size();i++){
     54         int y=nG[x][i];
     55         if(!b[y]){
     56             topoSort(y);
     57         }
     58         m[x]=max(m[x],m[y]);
     59     }
     60 }
     61 int main()
     62 {
     63 //    freopen("data.in","r",stdin);
     64     scanf("%d%d",&V,&E);
     65     for(int i=1;i<=E;i++){
     66         int x,y;
     67         scanf("%d%d",&x,&y);
     68         G[x].push_back(y);
     69         rG[y].push_back(x);
     70     }
     71     memset(b,0,sizeof(b));
     72     for(int i=1;i<=V;i++){
     73         if(!b[i]){
     74             dfs1(i);
     75         }
     76     }
     77     memset(b,0,sizeof(b));
     78     for(int i=vs.size()-1;i>=0;i--){
     79         cnt++;
     80         int x=vs[i];
     81         if(!b[x]){
     82             dfs2(x);
     83         }
     84     }
     85     memset(b,0,sizeof(b));
     86     for(int i=1;i<=V;i++){
     87         if(!b[i]){
     88             suo(i);
     89         }
     90     }
     91     memset(b,0,sizeof(b));
     92     for(int i=1;i<=cnt;i++){
     93         if(!ru[i]){
     94             topoSort(i);
     95         }
     96     }
     97     for(int i=1;i<=V;i++){
     98         printf("%d ",m[cmp[i]]);
     99     }
    100     return 0;
    101 }
    Code1

    T2:

    其实就是n-最大上升序列长度即可

    证明如下:

    设m=n-最长上升序列长度

    1)改变m次一定足以使数列递增

    2)改变不到m次一定不足以使数列递增

    依次证明:

    1)显然成立。。。

    2)不到m次,那么就设为x吧(x<m)

    那么假设x次操作改变的数列项为b1,b2,……,bx

    无视这x项,剩余的项数一定是递增的,即此时上升序列长度为n-x

    出现了矛盾:最长上升序列=n-m<n-x

    于是得证

    然后问题是最长上升序列我竟然有点忘记了

    巩固一下:

    建立单调栈,使得a[i]<a[i+1]

    对于新插入的元素a[i],查找大于等于(注意这里是大于等于,因为是严格递增的,所以不能出现相同)第一个a[Pos]

    f[i]=f[Pos-1]+1,然后直接用a[i]更新a[Pos],原因a[i]和a[Pos]的f相同的,但a[i]<=a[Pos],所以状态会更优

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<algorithm>
     4 #include<cstring>
     5 #define MAXN 100005
     6 #define pii pair<int,int>
     7 using namespace std;
     8 pii s[MAXN];
     9 int top=0;
    10 int a[MAXN];
    11 int f[MAXN];
    12 int n;
    13 int max_array(){
    14     int ret=0;
    15     for(int i=1;i<=n;i++){
    16         pii t=make_pair(a[i],0);
    17         // lower_bound the key should be the same
    18         int Pos=lower_bound(s+1,s+top+1,t)-s;
    19         f[i]=s[Pos-1].second+1;
    20         ret=max(f[i],ret);
    21         if(Pos>top){
    22             top++;
    23         }
    24         s[Pos]=make_pair(a[i],f[i]);
    25     }
    26     return ret;
    27 }
    28 int main()
    29 {
    30     scanf("%d",&n);
    31     for(int i=1;i<=n;i++){
    32         scanf("%d",&a[i]);
    33     }
    34     int len=n-max_array();
    35     printf("%d
    ",len);
    36     return 0;
    37 }
    Code2

    T3:

    这题我做过啊

    f[i][j]=f[i-1][j-1]*(i-j)+f[i-1][j]*(j+1)

    边界f[1~n][0]=1

    关键就是复习一下高精度了

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<algorithm>
     4 #include<cstring>
     5 #define MAXN 105
     6 #define SIZE 1000
     7 using namespace std;
     8 struct BigInt{
     9     int len;
    10     int s[SIZE];
    11     BigInt(){
    12         len=0;
    13         memset(s,0,sizeof(s));
    14     }
    15     BigInt operator = (const BigInt &A){
    16         len=A.len;
    17         for(int i=1;i<=len;i++){
    18             s[i]=A.s[i];
    19         }
    20         return *this;
    21     }
    22     friend BigInt operator * (const BigInt &A,const int B){
    23         BigInt t;
    24         t=A;
    25         int L=t.len;
    26         for(int i=1;i<=L;i++){
    27             t.s[i]*=B;
    28         }
    29         for(int i=1;i<=L;i++){
    30             t.s[i+1]+=(t.s[i]/10);
    31             t.s[i]%=10;
    32         }
    33         while(t.s[L+1]){
    34             L++;
    35             t.s[L+1]+=(t.s[L]/10);
    36             t.s[L]%=10;
    37         }
    38         t.len=L;
    39         return t;
    40     }
    41     friend BigInt operator + (const BigInt &A,const BigInt &B){
    42         BigInt t;
    43         t.len=max(A.len,B.len);
    44         int L=t.len;
    45         for(int i=1;i<=L;i++){
    46             t.s[i]=A.s[i]+B.s[i];
    47         }
    48         for(int i=1;i<=L;i++){
    49             t.s[i+1]+=(t.s[i]/10);
    50             t.s[i]%=10;
    51         }
    52         if(t.s[L+1]){
    53             L++;
    54         }
    55         t.len=L;
    56         return t;
    57     }
    58     void Print(){
    59         for(int i=len;i>=1;i--){
    60             printf("%d",s[i]);
    61         }
    62         printf("
    ");
    63     }
    64     
    65 }f[MAXN][MAXN];
    66 int n,k;
    67 int main()
    68 {
    69     scanf("%d%d",&n,&k);
    70     for(int i=1;i<=n;i++){
    71         f[i][0].len=1,f[i][0].s[1]=1;
    72     }
    73     for(int i=2;i<=n;i++){
    74         for(int j=1;j<n;j++){
    75             f[i][j]=f[i-1][j-1]*(i-j)+f[i-1][j]*(j+1);
    76         }
    77     }
    78     f[n][k].Print();
    79     return 0;
    80 }
    Code3

    总结:基础知识很重要啊,要不然真是有苦说不出。。。

  • 相关阅读:
    利用Trace.WriteLine定位难以重现的问题
    技术经验分享
    辞职小记
    残阳如血--读《忆秦娥·娄山关》 有感
    一个简单多线程等待窗口
    [转]Control的Invoke和BeginInvoke
    elk 改为使用 ik 中文分词器
    在 jenkins 的 pipeline 中使用分支参数
    centos8 下删除网桥 docker0
    vscode 实现组件之间的跳转
  • 原文地址:https://www.cnblogs.com/w-h-h/p/7604671.html
Copyright © 2011-2022 走看看