1. 程式人生 > >Codeforces Round #539 (Div. 2) 題解

Codeforces Round #539 (Div. 2) 題解

排序 多少 href include 只需要 偶數 possible 中間 pan

Codeforces Round #539 (Div. 2)

題目鏈接:https://codeforces.com/contest/1113

A. Sasha and His Trip

題意:

n個城市,城市分布在一條直線上且按升序排序,現在有個人開車從一號城市出發,車的油箱容量為v。

在每個城市都可以買油,但價格不一樣:第i個城市買1單位的油花費i元。問最終從1到n花費的最少為多少。

題解:

貪心即可,盡量在前面的城市買油,最後一鼓作氣到n號城市。

代碼如下:

技術分享圖片
#include <bits/stdc++.h>
using namespace std;
typedef 
long long ll; const int N = 2e5+5; int n,v; int main(){ cin>>n>>v; int fir=2,las=n-v; int ans=v; if(n-1<=v){ cout<<n-1; return 0; } for(int i=2;i<=las;i++){ ans+=i; } cout<<ans; return 0; }
View Code

B. Sasha and Magnetic Machines

題意:

給出n個數,現在選定i,j,然後取x滿足aj%x==0,之後讓aj=aj/x,ai=ai*x。這個操作最多一次,問最後所有數的和最小為多少。

題解:

由於這裏ai<=100,並且n也最多1e4,所以可以直接考慮暴力。但這裏暴力的是,取到一個x的時候,應該始終就是讓最小的那個ai來乘x,這應該是顯而易見的。

具體見代碼吧:

技術分享圖片
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5+5
; int a[N]; int n; int main(){ scanf("%d",&n); int sum = 0; for(int i=1;i<=n;i++){ scanf("%d",&a[i]); sum+=a[i]; } int ans = sum; int mn = *min_element(a+1,a+n+1); sum-=mn; for(int i=1;i<=n;i++){ for(int j=2;j<=a[i];j++){ if(a[i]%j!=0) continue ; ans=min(ans,sum-a[i]+a[i]/j+mn*j); } } cout<<ans; return 0; }
View Code

C. Sasha and a Bit of Relax

題意:

給出n個數,然後讓你找出滿足條件的區間個數:區間長度為偶數且區間左部分的異或和等於右部分的異或和。

題解:

根據題中條件可以知道,那整個區間的異或和是為0的,然後根據異或前綴和進一步可知:假設那個區間為[l,r],那麽prel-1=prer,這裏prei為1~i的異或前綴和。並且還可以觀察到,這裏的l-1以及r是同奇偶的。

然後做法也大致清晰了,找出在奇偶位置異或前綴和為x的個數,假設我們目前只看奇數位置,有n個,那麽這時對答案的貢獻為C(n,2),也即是n*(n-1)/2;偶數也同樣。

只是需要註意的是,當前綴異或和為0並且當前為偶數位置時,這也算一種情況。

具體代碼如下:

技術分享圖片
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int cnt[2][1<<20];
int main(){
    int n;
    cin>>n;
    vector <ll> a(n+2);
    for(int i=1;i<=n;i++) scanf("%I64d",&a[i]);
    ll sum=0,ans=0;
    cnt[0][0]=1;
    for(int i=1;i<=n;i++){
        sum^=a[i];
        ans+=cnt[i%2][sum];
        cnt[i%2][sum]++;
    }
    cout<<ans;
    return 0;
}
View Code

D. Sasha and One More Name

題意:

給出一個回文串,然後讓你用最少的次數分割為幾個部分,之後可以拼接出一個和原來不同的回文串。如果不能就輸出"Impossible",否則輸出最少次數。

題解:

不能的情況很好判斷。

在判斷可行性過後,可以證明次數最多只需要兩次,考慮從兩邊同時往中間走的切法就行了。

也就是說,我們只需要判斷只切一次是否可行。由於字符串的長度只有5000,O(n^2)暴力即可。

代碼如下:

技術分享圖片
#include <bits/stdc++.h>
using namespace std;
const int N = 5005;
string s;
int l;
bool is(string ss){
    int f=1;
    for(int i=0;i<l;i++){
        int j=l-i-1;
        if(ss[i]!=ss[j]) f=0;
    }
    return f&&ss!=s;
}
int main(){
    cin>>s;
    l=s.length();
    int f=1;
    for(int i=1;i<l;i++){
        if(l&1 && i==l/2) continue ;
        if(s[i]!=s[0]) f=0;
    }
    if(f){
        puts("Impossible");
        return 0;
    }
    f=0;
    for(int i=1;i<l;i++){
        string t1=s.substr(0,i),t2=s.substr(i,l);
        t2+=t1;
        if(is(t2))f=1;
    }
    if(f) cout<<1<<endl;
    else cout<<2<<endl;
    return 0;
}
View Code

Codeforces Round #539 (Div. 2) 題解