这一周打codeforces,我发现它出题真的秒~
自己做的题实在是太少了!orz 算法很好玩,都大二了,要加油鸭!冲冲冲
一周刷题记录挂上:
div2的A、B和div3的A、B、C差不多都考思维,每道题都很巧!
div2的C和div3的D就要用些算法知识了(很多都是当场问的dalao)
简单写一些dalao教我的题目的解题思路吧!
1.1435C Perform Easily
题目链接:https://codeforces.com/contest/1435/problem/C
题目大意:
吉他上有6根弦,给你a1,a2 , a3 , a4 , a5 , a6 每个弦上附上一个数字,然后给你n (1 ≤ n ≤ 100000)个数,b1, b2, ..., b3 (1 ≤ bi ≤ 109), 并且满足任意b大于a,每个数字都可以放在任意的弦上,
弦数(ai) + 品数 = bj 找所有的数组b都放到弦上后的最大和最小的品数的差值的最小值。
(写个题意好累orz)
样例解释:
第一行是各个弦的数字a: 1 1 2 2 3 3
第二行是要放到弦上的数字的数量n: 7
第三行是放上去的n个数字b: 13 4 11 12 11 13 12(有重复数字,放在一个点上即可)
13 --> 放在数为3的弦上 品:10
12 --> 放在数为3的弦上 品:9
12 --> 放在数为3的弦上 品:8
4 --> 放在数为1的弦上 品:3
最大品数和最小品数的差值: 7
解题思路:
因为有1e5个数,可以考虑暴力将所有的数字放在所有的弦上,求距离(O(6e5))放在一个pair数组中,pair的first存品数(方便sort排序),second存j(b数组的下标)。
利用sort使品数排序,然后进行一次从左向右遍历。找到n个下标都存在时的最大和最小值(相当于动态变化的一个n个数字的数组),不断根据它更新答案,找到最小的数组中的最大值-最小值。
这个动态数组找最大和最小值,dalao教我了两种方法:线段树 和 用map(自动排序) 存
而我线段树懒得写(忘的差不多了orz),就用的map。
map存储的是该品数的个数,并且用一个数组v存储当前该数字的数值,当需要更新该数字品数时,把之前的品数v[bb]从v中找到,并在map[v[bb]]--,当改品数的值为0的时候,要erase该品数(这点很重要),当num==n的时候,就可以更新ans了!
写完一个题了,耶耶耶!
AC代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <utility>
#include <map>
using namespace std;
int a[6];
map<int,int> mp;
const int maxn = 1e5+5;
int b[maxn];
typedef pair<int,int> PII;
PII s[maxn*6];
int v[maxn];
int main(){
for(int i=0;i<6;i++){
scanf("%d",&a[i]);
}
int n;
cin>>n;
for(int i=0;i<n;i++){
scanf("%d",&b[i]);
}
int len=0;
for(int i=0;i<6;i++){
for(int j=0;j<n;j++){
s[len++]={b[j]-a[i],j};
}
}
sort(s,s+len);
int num=0;
int ans=0x3f3f3f3f;
for(int i=0;i<len;i++){
int aa=s[i].first;
int bb=s[i].second;
if(v[bb]==0){
num++;
}
if(mp[v[bb]]>0)
mp[v[bb]]--;
mp[aa]++;
if(mp[v[bb]]==0){
mp.erase(v[bb]);
}
v[bb]=aa;
auto it=mp.begin();
if(num==n){
ans=min(ans,aa-it->first);
}
}
cout<<ans<<endl;
return 0;
}
C题太难写了,写个B题吧。思路依然很巧妙~
2.1421B题 Putting Bricks in the Wall
题目链接:https://codeforces.com/contest/1421/problem/B
题目大意:
一个人从S出发,想到达F,他可以上下左右进行移动,但只能选择0或者1进行移动(一旦选择,就不能更改)。必须防止他到达F,你最多可以更改2次(0改成1,或1改成0)。
样例解释:
4
S010
0001
1000
111F
->
S010
0001
1001
111F
//选择 1 或者 0 都无法到达 F
解题思路:
只需要把他的入口和出口改成相反的就可以了(入口全0,出口全1 或 入口全1,出口全0),仔细想一下,真是最多只需要两次改变。(我竟第一眼想的是dfs,bfs,老憨批了┮﹏┭)。
AC代码:
代码可能有点乱。
#include <iostream>
using namespace std;
const int maxn = 205;
char mp[maxn][maxn];
int main(){
int t;
cin>>t;
int n;
while(t--){
cin>>n;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cin>>mp[i][j];
}
}
char a=mp[1][0];
char b=mp[0][1];
char c=mp[n-1][n-2];
char d=mp[n-2][n-1];
if(a==b&&c==d){//0 1
if(a==c){
cout<<"2"<<endl;
cout<<"1 2"<<endl;
cout<<"2 1"<<endl;
}else{
cout<<"0"<<endl;
}
}
else{
if(a==d&&b==c){
cout<<"2"<<endl;
cout<<"1 2"<<endl;
cout<<n-1<<' '<<n<<endl;
}
else if(a==c&&b==d){
cout<<2<<endl;
cout<<"1 2"<<endl;
cout<<n<<' '<<n-1<<endl;
}
else if(a==b){
cout<<"1"<<endl;
if(c==a){
cout<<n<<' '<<n-1<<endl;
}
if(d==a){
cout<<n-1<<' '<<n<<endl;
}
}
else if(c==d){
cout<<1<<endl;
if(a==c){
cout<<"2 1"<<endl;
}
if(b==c){
cout<<"1 2"<<endl;
}
}
}
}
return 0;
}