Codeforces Round 1032 (Div. 3)(A-G)
题目链接:Dashboard - Codeforces Round 1032 (Div. 3) - Codeforces
A. Letter Home
思路
s要么在a之间要么在a之外,在中间的时候我们比较走到最左再走到最右和走到最右再走到最多即可,在外面的时候我们只需要输出其走到另一头的距离
代码
void solve(){int n,s;cin>>n>>s;vi a(n+10);for(int i=1;i<=n;i++){cin>>a[i];}if(s<=a[1]){cout<<a[n]-s<<"\n";return;}if(s>=a[n]){cout<<s-a[1]<<"\n";return;}cout<<min(a[n]-s+a[n]-a[1],s-a[1]+a[n]-a[1])<<"\n";
}
B. Above the Clouds
思路
很显然我们令b等于一个字符不断枚举即可
代码
void solve(){int n;string s;cin>>n>>s;s=" "+s;map<char,int> mp;mp[s[1]]++;mp[s[n]]++;for(int i=2;i<n;i++){mp[s[i]]++;if(mp[s[i]]>=2){cout<<"Yes\n";return;}}cout<<"No\n";
}
C. Those Who Are With Us
思路
可以肯定答案要么是最大值要么是最大值-1,只有当所有最大值都位于第r行和第c列我们选择(r,c)即可将答案变小,否则其他的所有情况都是最大值
这里我用的方法是统计最大值的数量,统计每一行或每一列最大值的个数,然后枚举所有点看其行与列的最大值个数加起来是否为总的最大值个数
代码
#include<bits/stdc++.h>
using namespace std;#define vcoistnt ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
#define int long long
#define vi vector<int>
#define vb vector<bool>
typedef pair<int,int> pll;const int N=2e5+10;
const int inf=1e18;
const int mod=998244353;void solve(){int n,m;cin>>n>>m;vector<vi> a(n+10,vi(m+10));int mx=0;for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){cin>>a[i][j];if(mx<a[i][j]) mx=a[i][j];}}int cnt=0;vi r(n+10);for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if(a[i][j]==mx) r[i]++,cnt++;}}vi c(m+10);for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if(a[i][j]==mx) c[j]++;}}for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if(a[i][j]!=mx){if(r[i]+c[j]==cnt){cout<<mx-1<<"\n";return;} }else{if(r[i]+c[j]==cnt+1){cout<<mx-1<<"\n";return;}}}}cout<<mx<<"\n";
}
signed main() {vcoistntcout<<fixed<<setprecision(2);int _=1;cin>>_;while(_--) solve();return 0;
}
D. 1709
思路
一道构造题,本来是打算构造成上面是1 2 3 4 ... 下面是n n+1 ...但发现操作次数会超
我们只需要先对a,b进行冒泡排序,然后对于每个a_i>b_i 的交换 a_i与b_i
那么到这里你的疑惑肯定是为什么可以直接交换ab而不影响其原来的顺序
我们可以分类讨论一下:
1.且
我们需要将两个都交换那么很明显不会影响
2.且
,我们需要交换
与
,因为
那么
,因为
那么
,因此没有影响
3.且
,我们需要交换
与
,因为
和
,因此没有影响
4.且
,符合题目要求不需要交换
代码
#include<bits/stdc++.h>
using namespace std;#define vcoistnt ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
#define int long long
#define vi vector<int>
#define vb vector<bool>
typedef pair<int,int> pll;const int N=2e5+10;
const int inf=1e18;
const int mod=998244353;void solve(){int n;cin>>n;vi a(n+10);vi b(n+10);for(int i=1;i<=n;i++){cin>>a[i];}for(int i=1;i<=n;i++){cin>>b[i];}vector<pll> ans;for(int i=2;i<=n;i++){int x=i;while(x>1&&a[x]<a[x-1]){ans.push_back({1,x-1});swap(a[x],a[x-1]);x--;}}for(int i=2;i<=n;i++){int x=i;while(x>1&&b[x]<b[x-1]){ans.push_back({2,x-1});swap(b[x],b[x-1]);x--;}}for(int i=1;i<=n;i++){if(a[i]>b[i]){ans.push_back({3,i});swap(a[i],b[i]);}}cout<<ans.size()<<"\n";for(auto [x,y]:ans){cout<<x<<" "<<y<<"\n";}
}
signed main() {vcoistntcout<<fixed<<setprecision(2);int _=1;cin>>_;while(_--) solve();return 0;
}
E. Sponsor of Your Problems
思路
从高位到低位知道遇到不相等的位数,相等的对答案的贡献为2,因为我们无法改变x的值使得其不同
遇到第一位不相等的,如果其相差大于1,我们对x的此位的取值可以取与l,r之间的某数使得贡献为零,对于后面的位数则就可以随便取了使其贡献为0
如果相差值为1我们需要往后继续找第一个不是9 0这种组合的 ,因为在之后如果是9 0的话x只能取9 或 0贡献为1
代码
#include<bits/stdc++.h>
using namespace std;#define vcoistnt ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
#define int long long
#define vi vector<int>
#define vb vector<bool>
typedef pair<int,int> pll;const int N=2e5+10;
const int inf=1e18;
const int mod=998244353;void solve(){string l,r;cin>>l>>r;int n=l.size();l=" "+l;r=" "+r;int i=1,ans=0;while(i<=n){int x=(l[i]-'0');int y=(r[i]-'0');if(x==y) ans+=2;else{if(x+1==y){ans++;i++;while(i<=n){int tx=(l[i]-'0');int ty=(r[i]-'0');if(tx==9&&ty==0){ans++;}else{break;}i++;}}break;}i++;}cout<<ans<<"\n";
}
signed main() {vcoistntcout<<fixed<<setprecision(2);int _=1;cin>>_;while(_--) solve();return 0;
}
F. Yamakasi
思路
此种类型题一般用前缀和来解决连续子数组和为某值的问题
对于第一个要求的实现,即或
,我们可以遍历一遍r的值,来寻找符合要求的
的个数
对于第二个要求的实现,我们要求此区间内最大值为x,那么我们不妨用lef来限制每个r前面的可用区间,即
当遇到我们清空统计的pre[l-1]的值并将lef移到r+1
当遇到我们将lef移到r+1并统计其pre[l-1]
当遇到不用处理
代码
#include<bits/stdc++.h>
using namespace std;#define vcoistnt ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
#define int long long
#define vi vector<int>
#define vb vector<bool>
typedef pair<int,int> pll;const int N=2e5+10;
const int inf=1e18;
const int mod=998244353;void solve(){int n,s,x;cin>>n>>s>>x;vi a(n+10);vi pre(n+10);for(int i=1;i<=n;i++){cin>>a[i];pre[i]=pre[i-1]+a[i];}int ans=0;map<int,int> cnt;int lef=1;for(int r=1;r<=n;r++){if(a[r]>x) cnt.clear(),lef=r+1;else if(a[r]==x){while(lef<=r){cnt[pre[lef-1]]++;lef++;}}ans+=cnt[pre[r]-s];}cout<<ans<<"\n";
}
signed main() {vcoistntcout<<fixed<<setprecision(2);int _=1;cin>>_;while(_--) solve();return 0;
}
G. Gangsta
思路
此题还是挺有意思的,做这个题的时候主要还是围绕着贡献来
解法一:
用的是线性dp和维护区间问题来解决此问题
如上图所示,我们在进行1--n每次加上最后一个0/1的时候对贡献进行处理,如果i位置上加上1,那么对于整体贡献的改变是i-1位置所有串的个数,同理加上0的时候是一样的
那么我们现在需要考虑的是如何动态的处理c_0,c_1以及个数,我们可以统计所有的的个数,
如图,我们如果要加入0,我们需要更新此数组,需要将出现次数向右移动一格,然后再令c0-c1=1的位置上+1,贡献T就变成了T=T+(>0出现的次数和),同理加1时要右移,将-1位置+1
那么现在我们要想办法将此数组进行维护,我们可以将数组下标进行+n处理,zero表示零点这样在进行左移和右移时只需要对zero进行+-即可,这样我们便能用树状数组和线段树对此数组进行维护(只涉及区间求和和单点修改)
解法二:
(官方解法)感觉此解法就比较抽象了
代码
解法一:
#include<bits/stdc++.h>
using namespace std;#define vcoistnt ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
#define int long long
#define vi vector<int>
#define vb vector<bool>
typedef pair<int,int> pll;const int N=4e5+10;
const int inf=1e18;
const int mod=998244353;vector<int> arr(N);
struct SegmentTree{vector<int> sum,tag;SegmentTree(int n):sum(4*n,0),tag(4*n,0){}void up(int i){sum[i] = sum[i << 1] + sum[i << 1 | 1];}void down(int i, int ln, int rn){if(tag[i] != 0){lazy(i << 1, tag[i], ln);lazy(i << 1 | 1, tag[i], rn);tag[i] = 0;}}void lazy(int i, int v, int n){sum[i] += v*n;tag[i] += v;}void build(int l, int r, int i){if(l == r){sum[i] = arr[l];}else{int mid = (l + r) >> 1;build(l, mid, i << 1);build(mid + 1, r, i << 1 | 1);up(i);}tag[i] = 0;}void add(int jobl, int jobr, int jobv, int l, int r, int i){if(jobl <= l && r <= jobr){lazy(i, jobv, r - l + 1);}else{int mid = (l + r) >> 1;down(i, mid - l + 1, r - mid);if(jobl <= mid){add(jobl, jobr, jobv, l, mid, i << 1);}if(jobr > mid){add(jobl, jobr, jobv, mid + 1, r, i << 1 | 1);}up(i);}}int query(int jobl, int jobr, int l, int r, int i){if(jobl <= l && r <= jobr){return sum[i];}int mid = (l + r) >> 1;down(i, mid - l + 1, r - mid);int ans = 0;if(jobl <= mid){ans += query(jobl, jobr, l, mid, i << 1);}if(jobr > mid){ans += query(jobl, jobr, mid + 1, r, i << 1 | 1);}return ans;}
};void solve(){int n;cin>>n;string s;cin>>s;s=" "+s;SegmentTree st(2*n+10);st.build(1,2*n+1,1);int zero=n+1;int x=0;int ans=0;for(int i=1;i<=n;i++){if(s[i]=='0'){zero--;st.add(zero+1,zero+1,1,1,2*n+1,1);x+=st.query(zero+1,2*n+1,1,2*n+1,1);}else{zero++;st.add(zero-1,zero-1,1,1,2*n+1,1);x+=st.query(1,zero-1,1,2*n+1,1);}ans+=x;}cout<<ans<<"\n";
}
signed main() {vcoistntcout<<fixed<<setprecision(2);int _=1;cin>>_;while(_--) solve();return 0;
}