【包河区2021初中组区赛】

1.排列

描述

序列A有N个元素,元素的范围从1到N(包含),也就是说(A1,A2,…,AN).请判断序列A是否为(1,2,3, …,N)的一个排列,也就是说,是(1,2,3,… ,N)中所有元素排成一列,不重复。例如(1,2,3)的排列有(1,2,3),(1,3,2)(2,1,3),(2,3,1),(3,1,2)(3,2,1)

输入

两行

第一行为一个正整数N,

第二行为N个正整数

输出

如果序列A是(1,2, ,N)的一个排列,输出“Yes” 否则,输出“No”

输入样例 1复制

5
3 1 2 4 5

输出样例1复制

Yes

输入样例 2复制

6
3 1 4 1 5 2

输出样例2复制

No

输入样例 3复制

3
1 2 3

输出样例3复制

Yes

输入样例 4复制

1
1

输出样例4复制

Yes

提示

【样例解释】

样例1解释:(3,1,2,4,5)是(1,2,3,4,5)的一个排列,所以输出:Yes

【数据范围】

1≤N≤10^3

1≤Ai≤N

#include<bits/stdc++.h>
using namespace std;
int main(){
	int a,t[10001]={0},n;
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>a;
		t[a]++;
	}
	for(int i=0;i<=10000;i++){
		if(t[i]>1){
			cout<<"No";
			return 0;
		}
	}
	cout<<"Yes";

	return 0;
	}

2.交换

描述

给定数组A,A有N个元素:A1,A2,…,AN,请找出符合以下条件数对的个数:

1≤i≤j≤N

Ai≠Aj

输入

两行

第一行为一个正整数N,

第二行为N个正整数

输出

打印出符合条件数对的个数

输入样例 1复制

3
1 7 1

输出样例1复制

2

输入样例 2复制

10
1 10 100 1000 10000 100000 1000000 10000000 100000000 1000000000

输出样例2复制

45

输入样例 3复制

20
7 8 1 1 4 9 9 6 8 2 4 1 1 9 5 5 5 3 6 4

输出样例3复制

173

提示

【样例解释】

样例1解释:

在这个数组中,A=(1,7,1)

对于数对(A1,A2)=(1,7),不等于

对于数对(A1,A3)=(1,1),等于

对于数对(A2,A3)=(7,1),不等于

因此,符合条件的数对有 2 个,输出 2

【数据范围】

2≤N≤3×10^5

1≤Ai≤10^9

这题双重for循环遍历肯定超时,使用map解决

超时代码:

#include<bits/stdc++.h>
using namespace std;
int main() {
  	long long n;
  	cin>>n;
  	long long a[n+5];
  	for(int i=0;i<n;i++){
    	cin>>a[i];
  	}
  	long long cnt=0;
  	for(long long i=0;i<n-1;i++){
    	for(long long j=i+1;j<n;j++){
      		if(a[i]!=a[j]){
        		cnt++;
      		}
   		}
	}
  	cout << cnt << endl;
 	return 0;
}

AC代码:


#include<bits/stdc++.h>
using namespace std;
long long cnt,u,ans;
map<long long,long long>a;
int main() {
	long long n;
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> u;
		a[u]++;
	}
    for(auto i=a.begin();i!=a.end();i++){
        if(i->second>=2){
           cnt+=(i->second*(i->second-1))>>1;
        }
    } 
    ans=(n*(n-1))>>1;
    cout<<ans-cnt;
	return 0;
}

3.排水

暴雨对城市的排水系统是严峻的考验。某城在台风到来之前对城市的排水系统进行检查。整个城市分为若干个区域,某片矩形区域配给某排查小组,他们打算分成若干次对这片区域的窨井进行检查第一次,他们从这片区域的左上角进入,从右下角出来,他们可以向右或向下行进,请问他们第一次最多能检查多少个窨井?地图中 0 表示正常道路,1 表示窨井。

输入

n+1 行,第 1 行两个正整数 n 和 m,表示地图的行数和列数,

接下来n 行,每行 m 个数字(0 或 1),中间用空格隔开,表示地图。

输出

一行,一个整数,表示最多可以查看的窨井数量。

输入样例 1复制

4 6
0 1 1 0 0 1
1 0 0 1 1 0
1 1 0 1 0 1
0 1 0 1 1 0

输出样例1复制

6

提示

【样例解释】

某条可以查看最多窨井数量的行走路线 :(1,1)->(2,1)->(3,1)->(3,2)->(4,2)->(4,3)->(4,4)->(4,5)->(4,6),在该路线上共有 6 个窨井。(3,2)表示第 3 行第 2 列的位置。

【数据范围】:

1≤n,m≤100

动态规划

#include<bits/stdc++.h>
using namespace std;
int maxn(int n, int m, const vector<vector<int>>& map) {
   vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));
    for (int i = 1; i <= n; i++) {
        if (map[i - 1][0] == 1) {
            dp[i][1] = dp[i - 1][1] + 1;
        } else {
            dp[i][1] = dp[i - 1][1];
        }
    }

    for (int j = 1; j <= m; j++) {
        if (map[0][j - 1] == 1) {
            dp[1][j] = dp[1][j - 1] + 1;
        } else {
            dp[1][j] = dp[1][j - 1];
        }
    }
    for (int i = 2; i <= n; i++) {
        for (int j = 2; j <= m; j++) {
            if (map[i - 1][j - 1] == 1) {
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + 1;
            } else {
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
            }
        }
    }

    return dp[n][m];
}

int main() {
    int n, m;
    cin >> n >> m;
    vector<vector<int>> map(n, vector<int>(m, 0));
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            cin >> map[i][j];
        }
    }

    int result = maxn(n, m, map);
    cout << result << endl;

    return 0;
}

4.回文

描述

给定正整数序列A=(A1​,A2​,…,AN​)。为了让它变成回文,你可以执行下列操作:

对于一个数对(x, y),把序列 A 中的所有 x 替换成 y这个操作可以不执行,也可以执行一次。请问最少需要执行多少次,能让 A 序列成为回文序列?

(回文序列——如果对每个 i(1≤i≤N), 都满足Ai​=AN+1−i​ )

输入

两行

第一行为一个正整数N,

第二行为N个正整数

输出

打印出最少需要执行的次数

输入样例 1复制

8
1 5 3 2 5 2 3 1

输出样例1复制

2

输入样例 2复制

7
1 2 3 4 1 2 3

输出样例2复制

1

输入样例 3复制

1
200000

输出样例3复制

0

提示

【样例解释】

样例1解释:

最初,序列 A=(1,5,3,2,5,2,3,1)

把 A 序列中所有的 3 替换成 2,A=(1,5,2,2,5,2,2,1)

把 A 序列中所有的 2 替换成 5,A=(1,5,5,5,5,5,5,1)

因此,通过两次操作,A 序列成为回文序列。而两次也是所需的最少次数。因此,输出 2

【数据范围】

1≤N≤2×10^5

1≤Ai​≤2×10^5

并查集,能在考场上写出来的都是勇士

#include<bits/stdc++.h>
using namespace std;
class uff{
public:
    vector<int> par;
    uff(int n) {
        par.resize(n + 1);
        for (int i = 1; i <= n; i++) {
            par[i] = i;
        }
    }

    int find(int x) {
        if (par[x] != x) {
            par[x] = find(par[x]);
        }
        return par[x];
    }

    void unite(int x, int y) {
        int rootX = find(x);
        int rootY = find(y);
        if (rootX != rootY) {
            par[rootX] = rootY;
        }
    }
};

int main() {
    int N;
    cin >> N;
    vector<int> A(N);
    for (int i = 0; i < N; i++) {
        cin >> A[i];
    }

    uff uf(2 * 100000); 

    int cnt = 0;
    int left = 0, right = N - 1;
    while (left < right) {
        int x = A[left];
        int y = A[right];

        int rootX = uf.find(x);
        int rootY = uf.find(y);

        if (rootX != rootY) {
            uf.unite(rootX, rootY);
            cnt++;
        }

        left++;
        right--;
    }

    cout << cnt << endl;

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值