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!!!!!

不会,咕咕咕

原文地址:https://www.cnblogs.com/dyhaohaoxuexi/p/14028288.html