Contest:https://codeforces.com/contest/1257
目錄
D-Yet Another Monster Killing Problem(思維+暴力)
A-Two Rival Students(暴力)
題目鏈接:https://codeforces.com/contest/1257/problem/A
題目大意:n個人,可以調換x次,兩個對手分別在位置a和b處,問最遠能夠讓對手距離多遠,每次換位置只能和身邊的人交換。
思路:最左邊的向左移動,最右邊的向右移動,直到沒有機會爲止。
ACCode:
int main(){
int T;scanf("%d",&T);
while(T--){
int n,x,a,b;scanf("%d%d%d%d",&n,&x,&a,&b);
if(a>b) swap(a,b);
for(x;x>=1&&a>=2;--x) --a;
for(x;x>=1&&b<=n-1;--x) ++b;
printf("%d\n",b-a);
}
}
B- Magic Stick(規律)
題目鏈接:https://codeforces.com/contest/1257/problem/B
題目大意:給出x和y。x有兩種操作:1.當且僅當x%2==0時,x=x*3/2。2.x=x-1;可以進行無限次操作,問x是否能變成y。
思路:首先容易發現,x=2時只能變成3,2,1。x=3時只能變成3,2,1。x=4時就是無限了。特判一下就好了。
ACCode:
int main(){
int T;scanf("%d",&T);
while(T--){
ll x,y;scanf("%lld%lld",&x,&y);
if(x>=y){
printf("YES\n");continue ;
}
if(x==1||x==3){
printf("NO\n");continue ;
}
if(x==2&&y>3){
printf("NO\n");continue ;
}
printf("YES\n");
}
}
C-Dominated Subarray(暴力)
題目鏈接:https://codeforces.com/contest/1257/problem/C
題目大意:給出n個元素的數組A。A的支配元素就是A中數量最多的元素。一個數組的支配元素只能有1個。現在求數組A的連續子數組,問最短的有支配元素的子數組的長度。
思路:很容易發現,找到最近的兩個相同的元素就好了。
ACCode:
int A[MAXN],Cnt[MAXN],Pre[MAXN];
int n;
int main(){
int Cas;scanf("%d",&Cas);
while(Cas--){
scanf("%d",&n);
for(int i=1;i<=n;++i) Cnt[i]=0;
for(int i=1;i<=n;++i) scanf("%d",&A[i]);
for(int i=1;i<=n;++i) Cnt[A[i]]++;
int maxcnt=0;
for(int i=1;i<=n;++i) maxcnt=max(maxcnt,Cnt[i]);//得到支配值的數量
if(maxcnt==1||n==1){
printf("-1\n");continue ;
}
for(int i=1;i<=n;++i) Cnt[i]=0,Pre[i]=-1;
int ans=n;
for(int i=1;i<=n;++i){
Cnt[A[i]]++;
if(Cnt[A[i]]==1){
Pre[A[i]]=i;
}
else{
ans=min(ans,i-Pre[A[i]]+1);
Pre[A[i]]=i;
}
}printf("%d\n",ans);
}
}
D-Yet Another Monster Killing Problem(思維+暴力)
題目鏈接:https://codeforces.com/contest/1257/problem/D
題目大意:給出n個怪物的防禦。m個英雄的攻擊p和耐力s。如果英雄的攻擊<怪物的防禦,沒有傷害,否則會直接秒殺怪物。英雄一次可以連續攻擊s下。問最後按順序消滅所有怪物,最少多少次英雄。同一個英雄可以使用多次。
思路:我們對耐力進行處理。Atk[i]表示耐力爲i的情況最高攻擊力是多少。這樣就可以枚舉怪物了。對於一次攻擊。枚舉耐力。找到最大的耐力滿足Atk[i]>=Hp[j]。就可以直接求出了。
ACCode:
int Atk[MAXN];
int Hp[MAXN];
int n,m;
int main(){
int T;scanf("%d",&T);
while(T--){
scanf("%d",&n);
for(int i=1;i<=n;++i) Atk[i]=0;
for(int i=1;i<=n;++i) scanf("%d",&Hp[i]);
scanf("%d",&m);
for(int i=1;i<=m;++i){
int p,s;scanf("%d%d",&p,&s);
if(Atk[s]<p) Atk[s]=p;//耐久爲s的最高攻擊力
}
for(int i=n-1;i>=1;--i){
Atk[i]=max(Atk[i],Atk[i+1]);
}
int flag=1,ans=0;
for(int pos=1,j;pos<=n;pos=j){
int maxhp=Hp[pos];
if(maxhp>Atk[1]){//該點總是過不去
flag=0;break;
}
for(j=pos;j<=n;++j){//最遠能走多遠
maxhp=max(maxhp,Hp[j]);//最大血量
if(Atk[j-pos+1]>=maxhp) continue ;//可以打這麼多下
//打不了這麼多下
break;
}ans++;
}
if(flag) printf("%d\n",ans);
else printf("-1\n");
}
}
E-The Contest(思維+DP)
題目鏈接:https://codeforces.com/contest/1257/problem/E
題目大意:給出三個人,一開始每個人有手頭都有ki個任務,然後給出每個人的手頭任務。但是,第一個人只完成連續的前n個。第二個人只完成連續的中間的。第三個人只完成連續的最後面的。問這些人需要將任務最少交換多少次才能滿足每個人的需求。
思路:注意有些人可以不完成任務,有些人可以完成所有的任務。先將每個人的任務排一下序
枚舉第一個人完成的任務個數,[0,i]。記錄一下要完成i個任務,需要丟棄多少任務Cnt1[i].
枚舉第三個人完成的任務個數,[i,n+1]。記錄一下要完成i個任務,需要丟棄的任務數量Cnt[i];
對於第二個人。我們容易發現:
當他要完成[l,n]個任務的時候。丟棄所有前面的任務Cntl2[l],必定丟棄到第一個人。而第一個人丟棄的任務必定給了第二個人,因此,可以得到,第一個人完成l個任務的時候,操作數爲Cnt1[l]+Cntl2[l];這時,第三個人一直是沒有任務的。
當他要完成[1,r]個任務的時候,丟棄後面的任務Cntr2[r]必定丟棄給第三個人。而第三個人必定丟棄給第二個人。因此同理可以得到:第三個人完成r個任務的時候,操作數爲Cnt3[r]+Cntr2[r];。這時,第一個人是一直沒有任務的。
最後,枚舉第一個人的任務數l。找到最小的操作數r加和,維護一下最小值即可。
ACCode:
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#include<time.h>
#include<math.h>
// srand((unsigned)time(NULL));rand();
#include<map>//unordered_map
#include<set>//multiset
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
#define ll long long
#define PII pair<int,int>
#define PLL pair<ll,ll>
#define clean(a,b) memset(a,b,sizeof(a))
using namespace std;
const int MAXN=2e5+10;
//const int MAXM=10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll MOD=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;
//unsigned register
// ios::sync_with_stdio(false)
int A[MAXN],B[MAXN],C[MAXN];
int Out1[MAXN],Out3[MAXN];
int Optl2[MAXN],Optr2[MAXN];
int n,k1,k2,k3;
int main(){
while(~scanf("%d%d%d",&k1,&k2,&k3)){
n=k1+k2+k3;
for(int i=1;i<=k1;++i) scanf("%d",&A[i]);
for(int i=1;i<=k2;++i) scanf("%d",&B[i]);
for(int i=1;i<=k3;++i) scanf("%d",&C[i]);
sort(A+1,A+1+k1);sort(B+1,B+1+k2);sort(C+1,C+1+k3);
int cnt=k1;
for(int i=0,j=1;i<=n;++i){//第一個人:[0,i]任務
while(j<=k1&&A[j]<=i) ++j,--cnt;
Out1[i]=cnt;
}
cnt=k3;
for(int i=n+1,j=k3;i>=1;--i){//第三個人:[i,n+1]任務
while(j>=1&&C[j]>=i) --j,--cnt;
Out3[i]=cnt;
}
// for(int i=0;i<=n;++i) printf("%d ",Out1[i]);puts("");
// for(int i=1;i<=n+1;++i) printf("%d ",Out3[i]);puts("");
cnt=0;
for(int i=1,j=1;i<=n;++i){//第二個人:[i,n] 凡是小於的都踢出去
while(j<=k2&&B[j]<i) ++j,++cnt;
Optl2[i]=cnt+Out1[i];
}
cnt=0;
for(int i=n,j=k2;i>=1;--i){//第二個人:[1,i] 凡是大於的都踢出去
while(j>=1&&B[j]>i) --j,++cnt;
Optr2[i]=cnt+Out3[i];
}
// printf("mid l:");for(int i=1;i<=n;++i) printf("%d ",Optl2[i]);puts("");
// printf("mid r:");for(int i=1;i<=n;++i) printf("%d ",Optr2[i]);puts("");
for(int i=n-1;i>=1;--i){
Optr2[i]=min(Optr2[i],Optr2[i+1]);
}
int ans=INF32;
for(int i=1;i<=n;++i){
ans=min(ans,Optl2[i]+Optr2[i]);
// printf("ans=%d\n",ans);
}printf("%d\n",ans);
}
}