zoukankan      html  css  js  c++  java
  • 2019ccpc-HN省赛-A/C/F/I

                     A.最大下降矩阵

    时间限制: 1 Sec  内存限制: 512 MB
    提交: 508  解决: 107
    [提交] [状态] [讨论版] [命题人:外部导入]
    题目描述
    我们称一个矩阵是下降矩阵,当且仅当,矩阵的每一列都是严格下降的。很显然,这个要求很苛刻,大多数矩阵都无法满足。但是显然如果消去一些行,一定可以使得这个矩阵变成下降矩阵。

    现在给出一个n行m列的矩阵,请你求出最少消去多少行,可以使得这个矩阵变为下降矩阵。
    输入
    输入第一行包含两个正整数n,m分别表示矩阵的行数和列数。(1<=n,m<=300)
    接下来n行,每行有m个数,中间用空格隔开,每个数都小于2^31.
    输出
    输出仅包含一个整数,即最少消去的行数。
    样例输入 Copy
    1 3
    1 2 3 
    样例输出 Copy
    0

     

     

        把每一行元素看作一个向量,或者说一个"行元素"。题目要求的就是对于N个向量来说的最长的严格下降子序列长度,然后用N减去这个严格下降子序列长度就是答案了。方法与求LIS类似。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 
     4 int N,M;
     5 int v[330][330];
     6 int f[330]={0};
     7 bool cmp(int di,int dj){
     8     for(int i=1;i<=M;++i){
     9         if(v[di][i] <= v[dj][i] ) return 0;
    10     }return 1;
    11 }
    12 int main()
    13 {
    14     cin>>N>>M;
    15     for(int i=1;i<=N;++i)
    16     for(int j=1;j<=M;++j)
    17     cin>>v[i][j];
    18     f[1]=1;
    19     int ans=1;
    20     for(int i=2;i<=N;++i){
    21         f[i]=1;
    22         for(int j=1;j<i;++j){
    23             if(cmp(j,i)){
    24                 f[i]=max(f[i],f[j]+1);
    25             }
    26         }
    27         ans=max(ans,f[i]);
    28     }
    29     cout<<N-ans<<endl;
    30     return 0;
    31 }

    问题 C: 大小接近的点对

    时间限制: 1 Sec  内存限制: 256 MB
    提交: 78  解决: 10
    [提交] [状态] [讨论版] [命题人:外部导入]
    题目描述
    一天,Chika 对大小接近的点对产生了兴趣,她想搞明白这个问题的树上版本,你能帮助她吗?Chika 会给 你一棵有根树,这棵树有 n 个结点,被编号为 1 n,1 号结点是根。每个点有一个权值,i 号结点的权值为 a[i]。如果 u 是 v 的祖先结点,并且 abs(a[u]−a[v]) ≤K,那么 (u,v) 被称作一个“** 大小接近的点对 **”。 对于树上的每个结点 i,你都需要计算以其为根的子树中的“大小接近的点对”的数量。你需要知道:  
    (1) abs(x) 代表 x 的绝对值。  
    (2) 每个结点都是其自身的祖先结点. 
     
    输入
    输入文件的第一行包含两个整数 n (1≤n≤105) 和 k (1≤k≤109),代表树中结点总数, 以及“大小接近的点对”的大小之差的上界。  
    第二行包含 n 个整数,第 i 个整数是 a[i] (1≤ a[i] ≤109),代表 i 号结点的权值。  
    第三行包含 n−1 个整数,第 i 个整数是 i+1 号结点的父结点。 

    输出
    输出应该包含n行,每一行包括一个整数。第i行的整数代表以i为根的子树中的“大小接近的点对”的数量。
    样例输入 Copy
    7 5
    2 4 4 1 4 6 4
    1 2 3 1 2 3
    样例输出 Copy
    19
    11
    5
    1
    1
    1
    1

         比赛的时候推出来是主席树了,奈何很久没写忘记关键步骤了= =

       先跑dfs先序对节点重新编号,然后按照新编号依次update,问题就转化为求在[L,R]编号区间内的满足a[u]-K<=x<=a[u]+K的x的数目。

      注意答案会爆int,很操蛋。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define LL long long 
     4 #define mid ((L+R)>>1)
     5 const int maxn=100010;
     6 int N,K;
     7 LL ans[maxn]; 
     8 int a[maxn],idx[maxn],_idx[maxn],cur=0,sons[maxn];
     9 vector<int>g[maxn];
    10 int root[maxn];
    11 int tot=0,ch[maxn*50][2];
    12 int sum[maxn*50];
    13 
    14 void update(int pre,int &now,int L,int R,int val){
    15     tot++;
    16     ch[tot][0]=ch[pre][0],ch[tot][1]=ch[pre][1];
    17     sum[tot]=sum[pre]+1,now=tot;
    18     //cout<<"now="<<now<<" "<<pre<<endl;
    19     if(L==R){
    20         return;
    21     }
    22     if(val<=mid){
    23         update(ch[pre][0],ch[now][0],L,mid,val);
    24     }
    25     else{
    26         update(ch[pre][1],ch[now][1],mid+1,R,val);
    27     }
    28 }
    29 int ask(int pre,int now,int L,int R,int l,int r){
    30     if(L>=l && R<=r){
    31         return sum[now]-sum[pre];
    32     }
    33     int res=0;
    34     if(r<=mid) res=ask(ch[pre][0],ch[now][0],L,mid,l,r);
    35     else if(l>mid) res=ask(ch[pre][1],ch[now][1],mid+1,R,l,r);    
    36     else{
    37         res=ask(ch[pre][0],ch[now][0],L,mid,l,r)+ask(ch[pre][1],ch[now][1],mid+1,R,l,r);;
    38     }
    39     return res;
    40 }
    41 /*void show(int id,int L,int R){
    42     cout<<L<<' '<<R<<' '<<sum[id]<<endl;
    43     if(L==R)return;
    44     if(ch[id][0])show(ch[id][0],L,mid);
    45     if(ch[id][1])show(ch[id][1],mid+1,R); 
    46 }*/
    47 void dfs(int u){
    48     idx[u]=++cur;
    49     _idx[cur]=u;
    50     sons[u]=1;
    51     for(auto v:g[u])dfs(v),sons[u]+=sons[v];
    52 }
    53 void solve(int u){
    54     ans[u]=ask(root[idx[u]-1],root[idx[u]-1+sons[u]],1,1000000000,max(1,a[u]-K),min(1000000000,a[u]+K));
    55     for(auto v:g[u]){
    56         solve(v);
    57         ans[u]+=ans[v];
    58     }
    59 }
    60 int main(){
    61     cin>>N>>K;
    62     for(int i=1;i<=N;++i)scanf("%d",a+i);
    63     for(int i=2,fa;i<=N;++i){
    64         scanf("%d",&fa);
    65         g[fa].push_back(i);
    66     }
    67     dfs(1);
    68     for(int i=1;i<=N;++i){
    69         update(root[i-1],root[i],1,1000000000,a[_idx[i]]);    
    70     }
    71     solve(1);
    72     for(int i=1;i<=N;++i)printf("%lld
    ",ans[i]);
    73     
    74     return 0;
    75 } 

    问题 F: 咕咕的计数题 II

    时间限制: 1 Sec  内存限制: 64 MB
    提交: 1108  解决: 69
    [提交] [状态] [讨论版] [命题人:外部导入]
    题目描述
    咕咕最近在学习初等数论,并且对下取整函数产生了极大的兴趣。下取整函数是指一个函数,自变量为 一个实数,因变量为一个整数,这个整数恰好是小于或等于自变量的最大的整数,通常记做 ⌊x⌋。例如, ⌊2.5⌋ = 2,⌊2⌋ = 2,⌊−2.5⌋ = −3。 
     咕咕发现,给定一个 a,并不是所有的自然数 n 都存在一个正整数 i 使得 ⌊n/i⌋ = a。那么,如果给定 l,r,咕咕好奇在区间 [l,r] 中有多少个正整数能使这个等式有正整数解 i 呢? 
     那么,聪明的你,你能告诉咕咕吗?  
    输入
    第一行有一个整数 T(1 ≤ T ≤ 106),表示数据组数。接下来有 T 行,每行有三个数 a,l,r(1 ≤ a ≤ 1018,1 ≤ l ≤ r ≤ 1018),表示一组询问。 
    输出
    输出 T 行,对每组询问,输出一个整数表示答案。 
    样例输入 Copy
    4
    5 7 10
    7 39 42
    1000 1000 1000
    27 100 1000
    
    样例输出 Copy
    1
    2
    1
    617
    
    提示
    数据范围 
    当 n = 39,a = 7 时,能找到 i = 5 使得 ⌊39 /5 ⌋ = 7。
     
     
      规律题,找规律or打表可以发现,这些满足条件的数字可以按照k*a分类,
      1,2......a......2a,2a+1......3a,3a+1,3a+2............a*a,....a*a+a-1......(a+1)*a......k*a......
     
      规律很容易发现,就是找不同的正整数k,那么从k*a开始往后的k个数字(包括k*a)只要在区间里面都是满足条件的,k等于多少就有多少个满足条件的数字,但注意当k>a的时候最多也只有a个数字而不是k个数字了
      利用容斥思想,找出[1,r]内的个数和[1,l-1]的个数做差就是答案。
    code:
     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define LL long long 
     4 LL T,a,l,r;
     5 LL solve(LL n){
     6     if(n<1) return 0;
     7     LL ans=0;
     8     LL div=n/a,rem=n%a;
     9     if(div<=a){
    10         ans+= div*(div-1)/2;
    11         if(div*a+div-1<=n){
    12             ans+=div;
    13         }
    14         else{
    15             ans+=(n-div*a+1);
    16         }
    17     }
    18     else{
    19         ans+=(1+a)*a/2;
    20         ans+=(div-a-1)*a;
    21         if(div*a+a-1<=n){
    22             ans+=a;
    23         }
    24         else{
    25             ans+=(n-div*a+1);
    26         }
    27     }
    28     return ans;
    29 }
    30 int main()
    31 {
    32     scanf("%lld",&T);
    33     while(T--){
    34         scanf("%lld%lld%lld",&a,&l,&r);
    35         printf("%lld
    ",solve(r)-solve(l-1));
    36     }
    37     return 0;
    38 }

    问题 I: Childhood dream

    时间限制: 1 Sec  内存限制: 256 MB
    提交: 63  解决: 18
    [提交] [状态] [讨论版] [命题人:zhd]
    题目描述
    你童年时期就有一个梦想,想要加入 ACM(Association of Calculation and Magic),今天,这个机会终于 来了。  
    但是 ACM 只想要哪些天赋异禀的人, 比如像 tourist,他们给了你一道题来检测你是否足够机智。  
    猜一个长度为 m 数字串,总共有 n 个提示串,解释如下: 
     8640 0A2B  
    A 前面的数字说明与答案相比,有多少个位置上的数字是相同的。 B 前面的数字说明与答案相比,有多 少个数字是相同的,但是位置不一样。 
     0 A 就表示给出的串没有任何位置和答案是相同的。 2 B 就表示给出的串中有两个数字和答案相同,但 是位置不一样。  
    所以,对于上面那个提示串 6457 是一个合理的答案,但是 1234 并不是。  
    现在给你 N(N<=100) 个提示串(如上所示),你需要去找到一个数字串来符合每一个提示串的要求。 
    提示串中的每个数字都是不同的,即一个串中不会存在相同的数字。  
    你能解决这个问题并加入 ACM 吗?  
    输入
    第一行两个数字,n(n<=100) 和 m(m<=9), 提示串的数量以及目标字符串的长度。  
    然后是 n 行,每行的格式如下:  
    s x y  
    s 是提示串,x 是 A 前的数字,y 是 B 前的数字,等同于:  
    s xAyB  
    输出
    一行,目标串。
    数据保证答案唯一。 
    样例输入 Copy
    6 4
    5164 3 0
    5174 3 0
    5194 3 0
    5124 3 0
    5134 3 0
    5104 3 0
    样例输出 Copy
    5184

    暴力搜索,由于不可行的情况很多,减枝会减去很多方案,所以直接搜完事。
    #include<bits/stdc++.h>
    using namespace std;
    
    char str[115][15]; 
    int A[115],B[115],tot[115][10];
    int N,M;
    int c[15];
    bool ok=0;
    bool check(int n,int type){
        for(int i=1;i<=N;++i){
            int _A=0,_B=0;
            for(int j=0;j<n-1;++j){
                if(str[i][j]-'0' == c[j+1]){
                    _A++;
                }
                else{
                    if(tot[i][c[j+1]]){
                        _B++;
                    }
                }
            }
            if(type==0 &&(_A>A[i]  || _B>B[i] )) return 0;
            if(type==1 &&(_A!=A[i] || _B!=B[i])) return 0;
        }
        return 1;
    }
    void dfs(int u){
        if(ok)return;
        if(!check(u,0)){
            return;
        }
        if(u==M+1){
            if(check(M+1,1)){
                ok=1;
                for(int i=1;i<=M;++i)cout<<c[i];cout<<endl;
            }
            return;
        }
        else{
            for(int i=0;i<10;++i){
                c[u]=i;
                dfs(u+1);
            }
        }
    }
    int main()
    {
        cin>>N>>M;
        for(int i=1;i<=N;++i){
            cin>>str[i]>>A[i]>>B[i];
        }
        for(int i=1;i<=N;++i){
            for(int j=0;j<M;++j){
                tot[i][str[i][j]-'0']++;
            }
        }
        dfs(1);
        return 0;
    }
     
  • 相关阅读:
    Linux第七节随笔 diff /uniq /stat
    部分命令积累
    Linux第六节随笔 输入输出重定向 、管道、通配符、wc / grep / tr / sort / cut / which /whereis /locate /find /
    单词记忆-3
    单词记忆-2
    特性
    Linux第五节随笔 /file / vim / suid /sgid sbit
    Linux第四节 组管理、用户管理、权限管理 / chmod /chown / umask / vim
    深入理解用户权限rwx
    Shell
  • 原文地址:https://www.cnblogs.com/zzqc/p/10704290.html
Copyright © 2011-2022 走看看