Codeforces Round 546 (Div. 2)
layout: post
title: Codeforces Round 546 (Div. 2)
author: "luowentaoaa"
catalog: true
tags:
mathjax: true
- codeforces
- 貪心
- 數(shù)學(xué)
- 線段樹
傳送門
A - Nastya Is Reading a Book (簽到)
題意
給出每一章的頁數(shù)范圍,然后告訴你當(dāng)前看到那一頁,求還沒看完的章節(jié)數(shù)目
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=1e9+7; const int maxn=2e5+50; const ll inf=1e17; typedef unsigned long long ull; int l[maxn],r[maxn]; int main() {int n;scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d%d",&l[i],&r[i]);int k;scanf("%d",&k);int num=n+1;for(int i=1;i<=n;i++){if(k>r[i])continue;else{num=i;break;}}cout<<n-num+1<<endl;return 0; }B - Nastya Is Playing Computer Games (模擬)
題意
一排井蓋,井蓋下面有金幣,你需要拿走所有金幣,拿走井蓋下的金幣需要井蓋上沒有石頭
一開始井蓋上面都有一個石頭。
每一秒你可以進(jìn)行以下一種操作
1:向左走或者向右走,
2:把一個石頭扔到其他任意一個井蓋上面
3:取走金幣
現(xiàn)在給你起始位置和井蓋個數(shù)
問你把所有金幣取走需要多少步
思路
很明顯的一個貪心策略,可以把所有石頭都扔到一個不需要的井蓋上面 但是第一個扔的還需要再扔回去
然后因為可能要會出生在中間點,所以可以貪心的選擇先向左還是向右走
首先 扔石頭肯定需要扔n+1次 ,金幣也需要撿n次,走路也需要走n-1次 然后就是重復(fù)走的距離min(n-k,k-1)
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=1e9+7; const int maxn=2e5+50; const ll inf=1e17; typedef unsigned long long ull;int main() {int n,k;scanf("%d%d",&n,&k);if(n==1||n==k)printf("%d\n",n*3);else{int sum=3*n;sum+=min((k-1),(n-k));printf("%d\n",sum);}return 0; }C - Nastya Is Transposing Matrices (神奇)
題意
矩陣a和b 每次可以把a(bǔ)的一個子矩陣按照左對角線翻轉(zhuǎn),問你能否使a變成b
思路
一開始題目的反轉(zhuǎn)理解錯了沒想到,
后來發(fā)現(xiàn) 如果對于一個2*2的矩陣一次反轉(zhuǎn)就相當(dāng)于把左下和右上對調(diào)。所以只需要保證這一條線的值都相同就肯定可以通過反轉(zhuǎn)變成B
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=1e9+7; const int maxn=2e5+50; const ll inf=1e17; typedef unsigned long long ull; vector<int>v1[500*500+5]; vector<int>v2[500*500+5]; int main() {int n,m;scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){int a;scanf("%d",&a);v1[i+j].push_back(a);}}for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){int a;scanf("%d",&a);v2[i+j].push_back(a);}}for(int i=1;i<=n+m;i++){sort(v1[i].begin(),v1[i].end());sort(v2[i].begin(),v2[i].end());if(v1[i]!=v2[i])puts("NO"),exit(0);}puts("YES");return 0; }D - Nastya Is Buying Lunch (貪心)
題意
給出一個1-n的數(shù)列,然后給你m個關(guān)系 如果前面的數(shù)正好在后面的數(shù)前面一個位置,那么就可以把這兩個數(shù)交換位置
問你最多可以讓最后一個數(shù)(a[n])向前走多少步
思路
首先我們可以把點分成兩類。
1:可以讓n和她交換位置
2:不可以讓n和她交換位置
那么題目就是讓n最后能有多少個連續(xù)的1類點
所以我們考慮貪心能不能把經(jīng)可能多的一類點向后移動
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=1e9+7; const int maxn=6e5+50; const ll inf=1e17; typedef unsigned long long ull;int a[maxn]; map<int,int>mp[maxn]; int vis[maxn]; int main() {int n,m;scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){scanf("%d",&a[i]);}for(int i=1;i<=m;i++){int u,v;scanf("%d%d",&u,&v);mp[u][v]=1;if(v==a[n])vis[u]=1;}for(int i=n-1;i>=1;i--){if(vis[a[i]]){for(int j=i+1;j<n;j++){if(mp[a[j-1]].find(a[j])!=mp[a[j-1]].end()){swap(a[j],a[j-1]);}else break;}}}int ans=0;for(int i=n-1;i>=1;i--){if(vis[a[i]])ans++;else break;}printf("%d\n",ans);return 0; }E - Nastya Hasn't Written a Legend (線段樹)
題意
給你兩個序列 \(a_1,a_2\dots a_n\) 和 $ k_1,k_2,\dots k_{n-1}\(,輸入保證\) a_{i}+k_{i}<=a_{i-1}$.
兩種操作:
1:區(qū)間求$ \sum_{i=l}^{r}a_i$
2:給單點$ a_i\(加\)x$ 同時會有連鎖反應(yīng),若\(a_p+k_p>a_{p+1}\),則\(a_{p+1}\) 更新為$ a_p+k_p$ ,同理更新到\(a_p+2\) 知道不能更新
思路
來自群友的做法 (感謝這位巨佬)
首先根據(jù)題意會發(fā)現(xiàn)一個式子
\[ a_1\leq a_2-k_1\leq a3-k_2-k_2 \dots \leq a_n-\sum_{i=1}^{n-1}k_i \]
給\(p\)位置加上值\(x\) 之后,\(a_p-\sum_{i=1}^{p-1}k_i\)也增加了x。更新之前已知\(a_p-\sum_{i=1}^{p-1}k_i\leq a_{p+1}-\sum_{i=1}^{p}k_i\) 如果\(a_p+k_p+x >a_{p+1}\)
那么\(a_{p+1}=a_p+k_p+x\) 并且\(a_{p+1}-\sum_{i=1}^{p}k_i=a_p-\sum_{i=1}^{p}k_i+x\) $a_{p+2} $同理
最后:
我們令\(b_x=a_x-\sum_{i=1}^{x-1}k_i\),我們給\(p\)單點加上\(x\)之后的效果:就是把\(i\in[p+1,n]\) 內(nèi)所有小于\(b_p+x\)的值賦值為\(b_p+x\)
所有修改我們已經(jīng)搞定了,用線段樹或者其他數(shù)據(jù)結(jié)構(gòu)維護(hù)就可以了,求和就是\(\sum_{i=l}^{r}b_i+\sum_{i=l}^{r}\sum_{j=1}^{i-1}k_j\) 更新就是區(qū)間賦值了,因為\(b_x\) 滿足單調(diào)不減性所以直接二分查找右端點
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=1e9+7; const int maxn=2e5+50; const ll inf=1e17; typedef unsigned long long ull;int n,m; ll a[maxn],k[maxn],ks[maxn]; struct SegTree{ll sum[maxn<<2],flag[maxn<<2];void build(int o,int l,int r){flag[o]=inf;if(l==r){sum[o]=a[l]-k[l-1];return;}int mid=(l+r)/2;build(o<<1,l,mid);build(o<<1|1,mid+1,r);sum[o]=sum[o<<1]+sum[o<<1|1];}void push_down(int o,int l,int r){if(flag[o]==inf)return;int mid=(l+r)/2;flag[o<<1]=flag[o<<1|1]=flag[o];sum[o<<1]=flag[o]*(mid-l+1);sum[o<<1|1]=flag[o]*(r-mid);flag[o]=inf;}void update(int o,int l,int r,int ql,int qr,ll v){if(ql<=l&&r<=qr){flag[o]=v;sum[o]=v*(r-l+1);return;}int mid=(l+r)/2;push_down(o,l,r);if(ql<=mid)update(o<<1,l,mid,ql,qr,v);if(qr>mid)update(o<<1|1,mid+1,r,ql,qr,v);sum[o]=sum[o<<1]+sum[o<<1|1];}ll query(int o,int l,int r,int ql,int qr){if(ql<=l&&r<=qr)return sum[o];int mid=(l+r)/2;push_down(o,l,r);ll res=0;if(ql<=mid)res+=query(o<<1,l,mid,ql,qr);if(qr>mid)res+=query(o<<1|1,mid+1,r,ql,qr);return res;} }segtree; int main() {scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%lld",&a[i]);for(int i=1;i<n;i++)scanf("%lld",&k[i]);for(int i=2;i<n;i++)k[i]+=k[i-1];for(int i=1;i<n;i++)ks[i]=ks[i-1]+k[i];segtree.build(1,1,n);scanf("%d",&m);while(m--){char op[5];int l,r;scanf("%s%d%d",op,&l,&r);if(op[0]=='s')printf("%lld\n",segtree.query(1,1,n,l,r)+ks[r-1]-(l>=2?ks[l-2]:0));else{int L=l,R=n,mid,ans=l;ll sum=segtree.query(1,1,n,l,l)+r;// cout<<"sum="<<sum<<endl;while(L<=R){mid=(L+R)/2;// cout<<"mid="<<mid<<endl;if(sum>segtree.query(1,1,n,mid,mid)){ans=mid;L=mid+1;}elseR=mid-1;}// cout<<"ans="<<ans<<endl;segtree.update(1,1,n,l,ans,sum);}}return 0; }轉(zhuǎn)載于:https://www.cnblogs.com/luowentao/p/10520658.html
總結(jié)
以上是生活随笔為你收集整理的Codeforces Round 546 (Div. 2)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: foot
- 下一篇: Oracle特殊恢复原理与实战(DSI系