zoukankan      html  css  js  c++  java
  • 2019年第五届CCPC中国大学生程序设计竞赛河南省赛

    A.最大下降矩阵

    题目:

    我们称一个矩阵是下降矩阵,当且仅当,矩阵的每一列都是严格下降的。很显然,这个要求很苛刻,大多数矩阵都无法满足。但是显然如果消去一些行,一定可以使得这个矩阵变成下降矩阵。

    现在给出一个n行m列的矩阵,请你求出最少消去多少行,可以使得这个矩阵变为下降矩阵。

    思路:

    直接按照求最长下降序列的方法来求,只是判断的时候暴力判断矩阵的一整行即可

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int N = 1e6 + 5;
    int n,m,a[305][305],dp[305],maxn=1;
    
    bool check(int i,int j){
        for(int k=1;k<=m;k++){
            if(a[i][k]>=a[j][k]){
                return false;
            }
        }
        return true;
    }
    
    int main(){
        cin>>n>>m;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                cin>>a[i][j];
            }
            dp[i]=1;
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=i;j++){
                if(check(i,j)){
                    dp[i]=max(dp[i],dp[j]+1);
                }
            }
            maxn = max(dp[i], maxn);
        }
        cout<<n-maxn<<endl;
        return 0;
    }
    

    B 树上逆序对

    一天,Chika 在研究关于所谓的树上逆序对的问题,你能帮助她吗?她会给你一棵有根树,这棵树有 n 个 结点,被编号为 1~ n,1 号结点是根。每个点有一个权值,i 号结点的权值为 a[i]。如果 u 是 v 的祖先结点, 并且 a[u] > a[v],那么 (u,v) 被称作一个“**逆序对 **”。
    Chika 会给你 m 个任务,包含两种类型:
    1 u x : 向树中添加一个新结点,其父亲为 u,权值为 x。执行完这个操作后,树的结点总数增加 1,因此该 结点的编号为 n+1(n 为添加这个点之前树中的总结点数)。
    2 u : 你需要回答如果删除以 u 为根的子树,树的剩余部分的逆序对数。任意两个类型 2 的任务之间互相 独立。
    你需要完成所有任务。

    不会,咕咕咕

    C 大小接近的点对

    题目:

    一天,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) 每个结点都是其自身的祖先结点.

    思路:

    离散化+树状数组+dfs

    走到当前节点时,记录一下([a_i-k,a_i+k])的点的数量,然后将自身加入树状数组,遍历子树后,再次查询([a_i-k,a_i+k])的点的数量,两者做差即为子树贡献的与当前节点配对的点,将其相加后返回即可

    #include<bits/stdc++.h>
    
    using namespace std;
    typedef long long LL;
    const int N = 3e5 + 5;
    vector<int> alls;
    vector<int> v[N];
    LL a[N],s[N],n,k;
    LL anss[N],c[N];
    int lowbit(int x) {
        return x & (-x);
    }
    
    // 单点修改
    void add(int x, int y) {
        for (int i = x+1; i <= alls.size(); i += lowbit(i)) c[i] += y;  // 不断往父节点跳
    }
    
    // 查询Sx前缀和
    LL query(int x) {
        LL res = 0;
        for (int i = x+1; i; i -= lowbit(i)) res += c[i];  // 不断往前一个兄弟节点跳
        return res;
    }
    
    int findx(LL x){
    	int l=0,r=alls.size()-1;
    	while(l<r){
    		int mid=(l+r)/2;
    		if(alls[mid]>=x){
    			r=mid;
    		}
    		else{
    			l=mid+1;
    		}
    	}
    	return r+1;
    }
    
    LL dfs(int now){
        anss[now] = 0;  //当前节点的答案数
        int l = findx(a[now] - k);
        int r = findx(a[now] + k);
        //cout << "l:" << query(l - 1) << "r:" << query(r) << endl;
        LL sum1 = query(r) - query(l - 1);
        int pos = findx(a[now]);
        add(pos, 1); //把自己加入树状数组
        for (int i = 0; i < v[now].size();i++){
            int ne = v[now][i];
            LL temp = dfs(ne);
            //cout << "temp:" << temp << endl;
            anss[now] += temp;
        }
        LL sum2 = query(r) - query(l - 1); //回溯时再查一遍
        anss[now] += sum2 - sum1;
        //cout << "now:" << now << "sum1:" << sum1 << "sum2:" << sum2 << "anss[now]:" << anss[now] << endl;
        return anss[now];
    }
    
    int main(){
        scanf("%lld%lld", &n, &k);
        for (int i = 1; i <= n;i++){
            scanf("%lld", &a[i]);
            alls.push_back(a[i]);
            alls.push_back(a[i]+k);
            alls.push_back(a[i]-k);
        }
        sort(alls.begin(),alls.end());
    	alls.erase(unique(alls.begin(),alls.end()),alls.end());  //离散化
        //cout << alls[0] << endl;
        for (int i = 1; i <= n - 1;i++){
            LL x;
            scanf("%lld", &x);
            v[x].push_back(i + 1);
        }
        dfs(1);
        //cout << endl;
        for (int i = 1; i <= n; i++)
        {
            printf("%lld
    ", anss[i]);
        }
        return 0;
    }
    

    D 文本修正

    签到

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int N = 1e6 + 5;
    string s;
    int main(){
        while(cin>>s){
            if(s=="henan"){
                cout << "Henan" << ' ';
            }
            else{
                cout << s << ' ';
            }
        }
        return 0;
    }
    

    E 咕咕的的复复读读机机

    签到

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int N = 1e6 + 5;
    int n,cnt[105],anss=0,maxn=0;
    int main(){
        cin >> n;
        while(n--){
            int x;
            cin >> x;
            cnt[x]++;
            if(cnt[x]>maxn){
                anss = x;
                maxn = cnt[x];
            }
        }
        cout << anss << endl;
        return 0;
    }
    

    F 咕咕的计数题 II

    咕咕最近在学习初等数论,并且对下取整函数产生了极大的兴趣。下取整函数是指一个函数,自变量为 一个实数,因变量为一个整数,这个整数恰好是小于或等于自变量的最大的整数,通常记做 ⌊x⌋。例如, ⌊2.5⌋ = 2,⌊2⌋ = 2,⌊−2.5⌋ = −3。
    咕咕发现,给定一个 a,并不是所有的自然数 n 都存在一个正整数 i 使得 ⌊n/i⌋ = a。那么,如果给定 l,r,咕咕好奇在区间 [l,r] 中有多少个正整数能使这个等式有正整数解 i 呢?
    那么,聪明的你,你能告诉咕咕吗?

    思路:

    找规律,对于一个a,符合⌊n/i⌋ = a的有 $a,2a,2a+1,3a,3a+1,3*a+2..... (等,另外还需要判断x与)a^2$的关系,值得注意的是一定要注意先除后乘,防止爆LL

    #include<bits/stdc++.h>
    
    using namespace std;
    typedef long long LL;
    const int N = 1e6 + 5;
    int t;
    LL a, l, r,res;
    LL solve (LL x){
        if(x/a<=a){  //先除后乘,防止爆LL
            long long pre = ((x / a - 1) + 1) * (x / a - 1) / 2;
            if((x/a)*a+(x/a)-1<x){
                return pre + (x / a);
            }
            else{
                return pre + x - (x / a) * a + 1;
            }
        }
        else{
            return a * (a - 1) / 2 + x - a * a + 1; //这里不用担心爆LL,因为x>a*a,说明a*a小于1e18
        }
    }
    
    int main(){
        cin >> t;
        while(t--){
            scanf("%lld%lld%lld", &a, &l, &r);
            res = solve(r)-solve(l-1);
            printf("%lld
    ", res);
        }
        return 0;
    }
    

    G 咕咕的 01 图

    不会,咕咕咕

    H 咕咕的搜索序列

    题意:

    给出一个dfs序,判断是否合法的dfs序的子序列

    思路:

    首先根据给出的dfs序设置遍历子树的优先顺序,然后再跑一遍dfs判断是否是子序列即可,至于怎么设置子树的优先顺序,直接在第一次dfs的时候由子节点更新父节点的顺序即可

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int N = 1e6 + 5;
    int t,n,m,order[N],anss[N],cnt,ep[N];
    vector<int> mp[N];
    
    void dfs(int now){
        for (int i = 0; i < mp[now].size();i++){
            dfs(mp[now][i]);
            order[now] = min(order[now], order[mp[now][i]]);
        }
    }
    
    bool cmp(int a,int b){
        return order[a] <= order[b];
    }
    
    void dfs2(int now){
        //cout << now << endl;
        for (int i = 0; i < mp[now].size();i++){
            dfs2(mp[now][i]);
        }
        anss[cnt++] = now;
    }
    
    int main(){
        scanf("%d", &t);
        while(t--){
            scanf("%d%d", &n, &m);
            for (int i = 1; i <= n;i++){
                order[i] = 0x3f3f3f3f;
                mp[i].clear();
            }
            for (int i = 2; i <= n; i++)
            {
                int x;
                scanf("%d", &x);
                mp[x].push_back(i);
            }
            for (int i = 1; i <= m;i++){
                scanf("%d", &ep[i]);
                order[ep[i]] = i;
            }
            dfs(1);
            for (int i = 1; i <= n;i++){
                sort(mp[i].begin(), mp[i].end(), cmp);
            }
            cnt = 0;
            dfs2(1);
            int pos = 0;
            for (int i = 1; i <= m;i++){
                while(anss[pos]!=ep[i]&&pos<n){
                    pos++;
                }
            }
            if (pos >= n)
            {
                cout << "BAD GUGU" << endl;
            }
            else{
                cout << "NOT BAD" << endl;
            }
        }
        return 0;
    }
    

    I Childhood dream

    题意:

    给出n个串,每个串还对应两个提示a和b,a代表这个提示串和正确答案有多少位置上的数是相同的,b代表有多少是数字相同但是位置不同的

    思路:

    没想到直接纯爆搜即可,题目说的是提示串中每个数字都是不同的,但是没有说答案串中都是不同的,但所有的题解都是按照答案串中数字都不同处理,不知道为什么,可能是题目不严谨把....

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int N = 100 + 5;
    int n, m,tips[N][15],A[N],B[N],vis[15],res[15];
    
    bool check(){
        for (int i = 0; i < n;i++){
            int a = 0, b = 0;
            for (int j = 0; j < m;j++){
                if(res[j]==tips[i][j]){
                    a++;
                }
                else {
                    for (int k = 0; k < m;k++){
                        if(res[j]==tips[i][k]){
                            b++;
                            break;
                        }
                    }
                }
            }
            if(a!=A[i]||b!=B[i]){
                return false;
            }
        }
        return true;
    }
    
    bool dfs(int step){
        if(step==m){
            //cout << 1 << endl;
            if(check()){
                for (int i = 0; i < m;i++){
                    cout << res[i];
                }
                cout << endl;
                return true;
            }
            else{
                return false;
             }
        }
        for (int i = 0; i <= 9;i++){
            if(vis[i])
                continue;
            vis[i] = 1;
            res[step] = i;
            if(dfs(step + 1)){
                //cout << i << endl;
                return true;
            }
                
            vis[i] = 0;
        }
        return false;
    }
    
    int main(){
        cin >> n >> m;
        for (int i = 0; i < n;i++){
            for (int j = 0; j < m;j++){
                scanf("%1d", &tips[i][j]);
            }
            scanf("%d%d", &A[i], &B[i]);
        }
        dfs(0);
        return 0;
    }
    

    J THE END IS COMING!!!!!

    不会,咕咕咕

  • 相关阅读:
    COGS 14. [网络流24题] 搭配飞行员
    洛谷 P3376 【模板】网络最大流
    洛谷 P2936 [USACO09JAN]全流Total Flow
    codevs 2038 香甜的黄油 USACO
    codevs 1993 草地排水 USACO
    Openjudge 2.5 6264:走出迷宫
    洛谷 P1744 采购特价商品
    HDU
    中国剩余定理
    bzoj2157: 旅游
  • 原文地址:https://www.cnblogs.com/dyhaohaoxuexi/p/14028288.html
Copyright © 2011-2022 走看看