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;
}