Codeforces Round 859 (Div. 4)
評價:比較簡單的一集,簡單考察思維和最基礎演算法
E:互動題。看了oiwiki和codeforces的文章,之前看的abc文章忘了,打算寫一篇總結特點和一些典型例題,還了解了其他題型。
Solution:回到本題:只需要利用字首和最佳化每次二分答案,從輸入裡得到我們想要的資訊
//cout.flush();
void solve(){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++){
a[i]+=a[i-1];
}
int l=1,r=n;
while(l<r){
cout<<"?"<<" ";
int mid=(l+r)>>1;
cout<<mid-l+1<<" ";
for(int i=l;i<=mid;i++)cout<<i<<" ";
cout<<endl;
//cout.flush();
int x;cin>>x;
if(a[mid]-a[l-1]!=x)r=mid;
else l=mid+1;
}
cout<<"!"<<" "<<l<<endl;
}
F:題意:給定一個\(n*m\)的矩陣,給定初始點的位置和速度方向,已經知道終點位置,問需要經過邊界反射多少次才能到達終點?
Solution:對於反射問題不難想到週期,我們考慮最差情況第二次到達起點的時候遍歷了所有方格點也就是\(n\times m\)個點,算上初始方向,最多有四個方向,所以最多經歷 \(4\times n\times m\)的路程,意思是最大週期是這麼多,再算下去一定會重複計算,沒有意義。每次到邊界的時候只需要判斷速度和位置會不會導致下一步越界,如果越界,則速度取相反方向。
void solve(){
cin>>n>>m;
int x1,y1,x2,y2;cin>>x1>>y1>>x2>>y2;
string s;cin>>s;
int mx=4*n*m;
int dx=0,dy=0;
if(s[0]=='D')dx=1;
else dx=-1;
if(s[1]=='R')dy=1;
else dy=-1;
int cux=x1,cuy=y1;
int cnt=0;
while(mx--){
if(cux==x2&&cuy==y2){
cout<<cnt<<endl;
return ;
}
bool flag=0;
if(cux==1&&dx==-1)dx=1,flag=true;
if(cux==n&&dx==1)dx=-1,flag=true;
if(cuy==1&&dy==-1)dy=1,flag=true;
if(cuy==m&&dy==1)dy=-1,flag=true;
cux+=dx;cuy+=dy;
if(flag)cnt++;
}
cout<<-1<<endl;
}
G:題意:Subsequence Addition (Hard Version)
數列 \(a\) 最開始只有一個數 \(1\),你可以進行若干次操作,每次操作你可以選取最新陣列中 \(k\) 個數(\(k\) 無限制,小於等於 \(a\) 的大小即可),將這 \(k\) 個數的和放入 \(a\) 的任意一個位置。
給定一個長度為 \(n\) 的序列 \(c\),問 \(a\) 能否在進行n-1次操作後轉為 \(c\)。
有 \(t\) 組資料。
\(1\leq \sum n\leq2\times10^5,1\leq c_i\leq2\times10^5,1\leq t\leq1000\)
Solution:由於是子序列,發現排序不影響答案正確性。以揹包視角思考問題,可以發現只要前i-1小
int n, m;
int a[N];
void solve(){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
int sum=1;
bool flag=true;
sort(a+1,a+1+n);
for(int i=1;i<=n;i++){
if(a[i]>sum)flag=false;
if(i>1) sum+=a[i];
}
if(flag)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}