题目传送
A Perfect
略
B Common(Easy Version)
C Common(Hard Version)
D Treasure
有一个 n 行 m 列的迷宫, 行数从上到下为 1 到 n, 列数从左到右为 1 到 m, 入口为 (1,1),
Reverie只能向上下左右四个方向行走。迷宫中有若干个宝箱。Reverie想知道,最少需要走多少步,才能找到一个宝箱。
第一行两个正整数 n, m, 表示迷宫的行数和列数。
之后 n 行,每行 m 个字符, ‘.’ 表示该位置是空地, ‘*’ 表示该位置是障碍, ‘#’ 表示该位置有一个宝箱。
保证点 (1,1) 是空地,宝箱所在的格子可以通过。
1
≤
n
,
m
≤
1000
1≤n,m≤1000
1≤n,m≤1000
一行内输出一个整数表示答案,如果没有宝箱或者所有宝箱位置均不可达,输出 -1.
BFS
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mp make_pair
#define pb push_back
ll gcd(ll a,ll b) { return !b?a:gcd(b,a%b);}
ll lcm(ll a,ll b){ return a/gcd(a,b)*b;}
int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};
int cnt = 0;
int r[1000+5][1000+5];
bool visited[1000+5][1000+5];
int res[1000+5][1000+5];
bool bfs(int i,int j){
queue<pair<int,int > > q;
q.push(mp(i,j));visited[i][j] = 1;
pair<int,int> t;
while(!q.empty()){
t = q.front();
i = t.first; j = t.second;
q.pop();
for(int k=0;k<4;k++){
int cx = i+dx[k],cy = j+dy[k];
if(r[cx][cy]&&!visited[cx][cy]){
cnt = res[i][j]+1;
res[cx][cy] = cnt;
visited[cx][cy]=1;
if(r[cx][cy]==2) return true;
else q.push(mp(cx,cy));
}
}
}
return false;
}
int main(){
int n,m;
cin >> n >> m;
memset(visited,0,sizeof(visited));
memset(r,0,sizeof(r));
char c;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
cin >> c;
if(c=='.') r[i][j] = 1;
else if(c=='#') r[i][j] = 2;
}
if(bfs(1,1)) cout << cnt << endl;
else cout << "-1" << endl;
return 0;
}
E Select
R
e
v
e
r
i
e
有
一
个
长
度
为
n
的
正
整
数
数
组
A
,
她
想
从
中
挑
出
一
些
数
字
,
Reverie有一个长度为 n 的正整数数组 A, 她想从中挑出一些数字,
Reverie有一个长度为n的正整数数组A,她想从中挑出一些数字,
使
得
这
些
数
字
的
和
最
大
,
选
中
的
任
意
两
个
数
字
在
原
数
组
中
不
能
相
邻
。
使得这些数字的和最大,选中的任意两个数字在原数组中不能相邻。
使得这些数字的和最大,选中的任意两个数字在原数组中不能相邻。
第
一
行
一
个
正
整
数
T
,
代
表
测
试
的
组
数
。
第一行一个正整数 T, 代表测试的组数。
第一行一个正整数T,代表测试的组数。
每
组
测
试
第
一
行
一
个
正
整
数
n
表
示
数
组
的
大
小
,
第
二
行
n
个
正
整
数
表
示
数
组
里
的
数
,
以
空
格
分
隔
。
每组测试第一行一个正整数 n 表示数组的大小,第二行 n 个正整数表示数组里的数,以空格分隔。
每组测试第一行一个正整数n表示数组的大小,第二行n个正整数表示数组里的数,以空格分隔。
1
≤
T
≤
100
1≤T≤100
1≤T≤100
1
≤
n
≤
1000
1≤n≤1000
1≤n≤1000
1
≤
A
i
≤
1000
1≤A_i≤1000
1≤Ai≤1000
状态转移方程:
d
p
[
0
]
=
a
[
0
]
,
d
p
[
1
]
=
m
a
x
(
a
[
0
]
,
a
[
1
]
)
dp[0]=a[0],dp[1]=max(a[0],a[1])
dp[0]=a[0],dp[1]=max(a[0],a[1])
d
p
[
i
]
=
m
a
x
(
d
p
[
i
−
1
]
,
d
p
[
i
−
2
]
+
a
[
i
]
)
dp[i]=max(dp[i-1],dp[i-2]+a[i])
dp[i]=max(dp[i−1],dp[i−2]+a[i])
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
int T;
cin >> T;
while(T--){
int n;
cin >> n;
int a[n],dp[n+2];
memset(dp,0,sizeof(dp));
for(int i=0;i<n;i++)
cin >> a[i];
dp[0] = a[0];
dp[1] = max(a[0],a[1]);
for(int i=2;i<n;i++)
dp[i] = max(dp[i-2]+a[i],dp[i-1]);
cout << dp[n-1] << endl;
}
return 0;
}
F Swap(Easy Vesion)
R
e
v
e
r
i
e
有
一
个
字
符
串
,
她
每
次
操
作
可
以
交
换
其
中
任
意
相
邻
两
个
字
符
的
位
置
。
Reverie有一个字符串,她每次操作可以交换其中任意相邻两个字符的位置。
Reverie有一个字符串,她每次操作可以交换其中任意相邻两个字符的位置。
R
e
v
e
i
r
e
想
知
道
,
把
这
个
字
符
串
变
成
字
典
序
最
小
至
少
需
要
多
少
次
操
作
。
Reveire想知道,把这个字符串变成字典序最小至少需要多少次操作。
Reveire想知道,把这个字符串变成字典序最小至少需要多少次操作。
第
一
行
一
个
正
整
数
T
,
代
表
测
试
的
组
数
。
第一行一个正整数 T, 代表测试的组数。
第一行一个正整数T,代表测试的组数。
每
组
测
试
,
一
行
内
给
出
一
个
仅
包
含
小
写
字
母
的
字
符
串
s
。
每组测试,一行内给出一个仅包含小写字母的字符串 s。
每组测试,一行内给出一个仅包含小写字母的字符串s。
1
≤
T
≤
10
1≤T≤10
1≤T≤10
1
≤
∣
s
∣
≤
1000
1≤∣s∣≤1000
1≤∣s∣≤1000
最小交换次数即逆序对数
下面使用两重循环暴力求解
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll res = 0 ;
char a[1000005];
int main(){
int t;
cin >> t;
getchar();
while(t--){
res = 0;
scanf("%s",a);
int n = strlen(a);
for(int i=0;i<n;i++){
for(int j=0;j<i;j++){
if(a[j]>a[i]){
res ++;
}
}
}
cout << res << endl;
}
return 0;
}
G Swap(Hard Vesion)
数据范围改变
1
≤
T
≤
10
1≤T≤10
1≤T≤10
1
≤
∣
s
∣
≤
100000
1≤∣s∣≤100000
1≤∣s∣≤100000
暴力不可行,会超时,使用归并排序求逆序对数
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
/*
归并排序求逆序对
*/
ll res = 0 ;
char a[1000005];
char b[1000005];
void merge(char a[],int low,int mid,int high){
int i = low,j = mid +1,k = 0;
while(i<=mid&&j<=high){
if((a[i]-'a')<=(a[j]-'a')) b[k++] = a[i++];
else {
b[k++] = a[j++];
res += (mid-i+1); // 是mid-i+1 而非j-i
}
}
while(i<=mid){
b[k++] = a[i++];
}
while(j<=high){
b[k++] = a[j++];
}
k = 0;
for(i=low;i<=high;i++,k++){
a[i] = b[k];
}
}
void merge_sort(char a[],int low, int high){
int mid;
if(low < high){
mid = (low+high)/2;
merge_sort(a,low,mid);
merge_sort(a,mid+1,high);
merge(a,low,mid,high);
}
}
int main(){
int t;
cin >> t;
getchar();
while(t--){
res = 0;
scanf("%s",a);
merge_sort(a,0,strlen(a)-1);
cout << res << endl;
}
return 0;
}
H Operator
R
e
v
e
r
i
e
有
一
个
长
度
为
n
的
整
数
数
组
A
,
她
想
在
每
两
个
数
之
间
填
入
Reverie有一个长度为n的整数数组A,她想在每两个数之间填入
Reverie有一个长度为n的整数数组A,她想在每两个数之间填入
‘
+
’
或
者
‘
−
’
,
使
得
最
终
运
算
结
果
尽
可
能
接
近
给
定
的
评
估
值
k
.
‘+’ 或者 ‘-’, 使得最终运算结果尽可能接近给定的评估值 k.
‘+’或者‘−’,使得最终运算结果尽可能接近给定的评估值k.
I
n
p
u
t
Input
Input
第
一
行
一
个
正
整
数
T
,
代
表
测
试
的
组
数
。
第一行一个正整数 T, 代表测试的组数。
第一行一个正整数T,代表测试的组数。
每
组
测
试
,
第
一
行
两
个
整
数
n
,
k
分
别
表
示
数
组
的
大
小
和
给
定
的
评
估
值
,
每组测试,第一行两个整数 n, k 分别表示数组的大小和给定的评估值,
每组测试,第一行两个整数n,k分别表示数组的大小和给定的评估值,
第
二
行
n
个
正
整
数
表
示
数
组
里
的
数
,
以
空
格
分
隔
。
第二行 n 个正整数表示数组里的数,以空格分隔。
第二行n个正整数表示数组里的数,以空格分隔。
1
≤
T
≤
10
1≤T≤10
1≤T≤10
2
≤
n
≤
20
2≤n≤20
2≤n≤20
1
≤
k
,
A
i
≤
1
0
6
1≤k,A_i≤10^6
1≤k,Ai≤106
O
u
t
p
u
t
Output
Output
每
组
测
试
,
一
行
内
输
出
一
个
整
数
表
示
运
算
结
果
与
k
的
差
值
的
绝
对
值
的
最
小
值
。
每组测试,一行内输出一个整数表示运算结果与 k 的差值的绝对值的最小值。
每组测试,一行内输出一个整数表示运算结果与k的差值的绝对值的最小值。
S a m p l e I n p u t Sample Input SampleInput
2
3 7
3 6 9
4 6
1 2 3 4
S a m p l e O u t p u t Sample Output SampleOutput
1
0
DFS即可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll inf = 0x3f3f3f3f;
const int maxn = 200;
char best[maxn];
void dfs(int a[],int n,int sum,int i,char op[],int tar){
if(i==n){
if(abs(sum-tar)<abs(inf-tar)){
inf = sum;
for(int i=1;i<n;i++)
best[i] = op[i];
}
return ;
}
sum += a[i];
op[i] = '+';
dfs(a,n,sum,i+1,op,tar);
sum -= a[i];
sum -= a[i];
op[i] = '-';
dfs(a,n,sum,i+1,op,tar);
sum += a[i];
}
int main(){
int t;
cin >> t;
getchar();
while(t--){
int n; cin >> n;
ll tar; cin >> tar;
int a[n];
for(int i=0;i<n;i++)
cin >> a[i];
char op[n];
dfs(a,n,a[0],1,op,tar);
ll res = a[0];
for(int i=1;i<n;i++){
if(best[i]=='+')
res += a[i];
else if(best[i]=='-')
res -= a[i];
}
cout << abs(res-tar) << endl;
inf = 0x3f3f3f3f; // 记得修改inf的值
}
return 0;
}