# Codeforces Round #933 (div.3) 紀錄
*(補) 比賽日期: 03/11*
## 賽中作答
> 賽中答題數:3/7 賽後答題數:6/7
> 賽中作答順序: 1->4->5->2->3
### 第一題
第一題是很簡單的枚舉題,只要一一計算所有b[i]+c[j]小於等於k的數即可。
不過在提交的時候發生了一點意外
傳送的結果是Compilation error
一開始還以為是程式碼出狀況
稍微修改後結果還是一樣
最後才發現是編譯器選錯
再次提交後就AC了
#### 程式碼
```cpp=
#include<iostream>
#include<vector>
#define F first
#define S second
#define ll long long
#define pii pair<int,int>
#define mkp(a,b) make_pair(a,b)
#define runrun ios_base::sync_with_stdio(false);cin.tie(0);
using namespace std;
int n,m,k,in;
void solve(){
cin>>n>>m>>k;
vector<int> b,c;
for(int i=0;i<n;i++){
cin>>in;
b.push_back(in);
}
for(int i=0;i<m;i++){
cin>>in;
c.push_back(in);
}
ll ans=0;
for(int i=0;i<n;i++){
for(int j=0;j<m;++j){
if(b[i]+c[j]<=k){
++ans;
}
}
}
cout<<ans<<"\n";
}
int main(){
int t;
cin>>t;
while(t--){
solve();
}
return 0;
}
```
### 第四題
#### 題目敘述:
有編號1到n總共n個人,他們圍繞在一起。編號x的人有一顆球
接下來有m行輸入,其中包含數字r和字元c
如果c== '0',那麼拿著球的人就會往順時針方向投擲,投給(x+r)%n編號的人
如果c== '1',那麼拿著球的人就會往逆時針方向投擲,投給(x-r+n)%n編號的人
如果c== '?',那麼拿著球的人就有可能往順時針或逆時針方向投擲。更仔細的說,拿到球的人可能是編號(x+r)%n或編號(x-r+n)%n的人,
試問最後可能拿到球的人共有幾人,並輸出他們的編號
由於題目有給一個n×m不會超過2e5的條件,所以可以很快速的想到應該是複雜度O(nm)的做法
知道這個條件後,我們就可以這樣做:用陣列記錄每個當下可能拿到球的人,判斷他們可以投到的位置,將處於這個位置的人設為下一個拿到球的人
#### 程式碼
```cpp=
#include<bits/stdc++.h>
#define F first
#define S second
#define ll long long
#define pii pair<int,int>
#define mkp(a,b) make_pair(a,b)
#define runrun ios_base::sync_with_stdio(false);cin.tie(0);
using namespace std;
int n,m,x;
void solve(){
cin>>n>>m>>x;
vector<int> dp(n,0);
vector<int> memo,memo2;
dp[x-1]=1;
memo.push_back(x-1);
char c;
for(int i=0,d;i<m;i++){
cin>>d>>c;
for(int j=0;j<n;j++){
int r=(j-d+n)%n,l=(j+d)%n;
if((c=='0'||c=='?')&&dp[r]==1){
memo2.push_back(j);
}
if((c=='1'||c=='?')&&dp[l]==1){
memo2.push_back(j);
}
}
for(auto v:memo){
dp[v]=0;
}
for(auto v:memo2){
dp[v]=1;
}
swap(memo,memo2);
memo2.clear();
}
int cnt=0;
for(int i=0;i<n;i++){
if(dp[i]==1) cnt++;
}
cout<<cnt<<"\n";
for(int i=0;i<n;i++){
if(dp[i]==1) cout<<i+1<<" ";
}
cout<<"\n";
}
int main(){
runrun;
int t;
cin>>t;
while(t--) solve();
return 0;
}
```
### 第五題
賽中寫這題時完全卡住了==,剩二十分鐘才回去前面補題
### 第二題
滿直覺的greedy題,從左到右計算,如果遇到大於0的數字,那麼就分別對ak,ak+1,ak+2減去1,2,1;如果遇到等於0的數字,那就跳到下一個數字;如果遇到小於0的數字或者n-2或n-1的數字是正數的時候,那麼這個序列就是不成立的
#### 程式碼
```cpp=
#include<iostream>
#include<vector>
#define F first
#define S second
#define ll long long
#define pii pair<int,int>
#define mkp(a,b) make_pair(a,b)
#define runrun ios_base::sync_with_stdio(false);cin.tie(0);
using namespace std;
void solve(){
int n;
cin>>n;
vector<int> vec(n);
for(int i=0;i<n;i++) cin>>vec[i];
bool f=true;
int p=0;
while(p<n){
if(vec[p]==0) p++;
else if(vec[p]>0&&p<n-2){
vec[p+1]-=vec[p]*2;
vec[p+2]-=vec[p];
vec[p]=0;
}
else{
f=false;
break;
}
}
if(f){
cout<<"YES\n";
}
else{
cout<<"NO\n";
}
}
int main(){
runrun
int t;
cin>>t;
while(t--) solve();
return 0;
}
```
### 第三題
這題條件判斷比較複雜,而且我在寫這題時已經剩不到十分鐘了,所以最後我是沒有做出來的 :(
## 賽後補題
> 賽中答題數:3/7 賽後答題數:6/7
> 賽後補題順序: 3->5->6
### 第三題
這題真的不難,可惜最後時間緊湊,腦子一時間轉不過來。題目要求字串總共有幾個完整的map跟pie。除了記錄這兩個單字之外,還要考慮出現mapie的情況,所以只要用五個字元記錄,然後做出對應的判斷就行
#### 程式碼
```cpp=
#include<bits/stdc++.h>
#define pii pair<int,int>
#define F first
#define S second
#define mkp(a,b) make_pair(a,b)
using namespace std;
void solve(){
int n,ans=0;
string S;
cin>>n>>S;
char c[5]={'0','0','0','0','0'};
for(int i=0;i<n;i++){
for(int j=0;j<4;j++){
c[j]=c[j+1];
}
c[4]=S[i];
if(c[2]=='p'&&c[3]=='i'&&c[4]=='e'){
ans++;
}
if(c[2]=='m'&&c[3]=='a'&&c[4]=='p'){
ans++;
}
if(c[0]=='m'&&c[1]=='a'&&c[2]=='p'&&c[3]=='i'&&c[4]=='e'){
ans--;
}
}
cout<<ans<<"\n";
}
int main(){
ios_base::sync_with_stdio(false);cin.tie(0);
int t;
cin>>t;
while(t--){
solve();
}
return 0;
}
```
### 第五題
仔細閱讀題目敘述之後,我才發現我比賽時理解錯題意了。題目要求製造連續k座橋最小所需花費的成本。製作一座橋所需的最小成本可以用單調序列得到,而計算連續的成本只要簡單的用陣列記錄就行了
#### 程式碼
```cpp=
#include<bits/stdc++.h>
#define F first
#define S second
#define ll long long
#define pii pair<ll,ll>
#define mkp(a,b) make_pair(a,b)
#define runrun ios_base::sync_with_stdio(false);cin.tie(0);
using namespace std;
void solve(){
int n,m,k,d;
cin>>n>>m>>k>>d;
vector<vector<ll> > road(n,vector<ll>(m));
vector<pii> A;
for(int i=0;i<n;i++){
deque<pii> deq;
for(int j=0;j<m;j++){
cin>>road[i][j];
if(j==0){
deq.push_back(mkp(1,0));
continue;
}
while(!deq.empty()&&deq.front().S<j-d-1){
deq.pop_front();
}
ll cnt=road[i][j]+deq.front().F+1;
while(!deq.empty()&&deq.back().F>=cnt){
deq.pop_back();
}
deq.push_back(mkp(cnt,j));
}
A.push_back(deq.back());
}
ll ans=2e18,tmp=0,cnt=0;
for(int i=0;i<n;i++){
cnt++;
tmp+=A[i].F;
if(cnt>=k){
if(ans>tmp) ans=tmp;
tmp-=A[i-k+1].F;
}
}
cout<<ans<<"\n";
}
int main(){
int t;
cin>>t;
while(t--){
solve();
}
return 0;
}
```
### 第六題
這題想法單純,實作卻有很多細節,以下是我的想法:
* 紀錄a陣列數字間距離最大d1和次大d2,還有最大距離旁的兩個數字nex跟pre
* 如果d1==d2的話,那麼答案必定為d1
* 否則,對陣列f進行排序
* 完成排序後,我們就可以對陣列f進行二分搜
* 那要搜什麼呢?
* 我們的目標是找到d[i]+f[j]放入陣列a,使陣列間的數字間距離最小
* 同時我們知道:如果在陣列a放入一個(nex+pre)/2的數字,其命名為tar,那麼tar就會落在nex跟pre之間,並且d1的距離必定減少最多
* 知道這些後,我們就可以用二分搜尋找有沒有符和或靠近tar的組合,得到這兩個數字間可分割成的距離
* 最後,這些計算後的距離還要跟d2比較,答案就是這些數字中的最大值
#### 程式碼
```cpp=
#include<bits/stdc++.h>
#define F first
#define S second
#define int long long
#define pii pair<int,int>
#define mkp(a,b) make_pair(a,b)
#define runrun ios_base::sync_with_stdio(false);cin.tie(0);
using namespace std;
int v,n,m,dis=0,pre,nex,sec;
vector<int> a,d,k;
int bsearch(int v,int tar){
int l=0,r=m-1,mid;
while(l<=r){
mid=(l+r)/2;
if(v+k[mid]>tar){
r=mid-1;
}
else if(v+k[mid]<=tar){
l=mid+1;
}
}
int ans=dis;
if(l<m) ans=min(ans,max(v+k[l]-pre,nex-(v+k[l]) ));
if(r>=0) ans=min(ans,max(v+k[r]-pre,nex-(v+k[r]) ));
if(ans<sec) ans=sec;
return ans;
}
int solve(){
int in;
cin>>v>>n>>m;
dis=0;
sec=0;
a.clear();
d.clear();
k.clear();
for(int i=0;i<v;i++){
cin>>in;
a.push_back(in);
if(i>0){
if(dis<=a[i]-a[i-1]){
pre=a[i-1]; nex=a[i];
sec=dis;
dis=a[i]-a[i-1];
}
else if(sec<a[i]-a[i-1]){
sec=a[i]-a[i-1];
}
}
}
for(int i=0;i<n;i++){
cin>>in;
d.push_back(in);
}
for(int i=0;i<m;i++){
cin>>in;
k.push_back(in);
}
if(dis==sec) return dis;
sort(k.begin(),k.end());
int ave=(pre+nex)/2;
int ans=2e9+5;
for(int i=0;i<n;i++){
ans=min(ans,bsearch(d[i],ave));
}
return ans;
}
signed main(){
runrun
int t;
cin>>t;
while(t--){
cout<<solve()<<"\n";
}
return 0;
}
```
*(補) 截稿日期:03/21*