1. 程式人生 > >Codeforces Round #515 (Div. 3) ABCDEF比賽總結

Codeforces Round #515 (Div. 3) ABCDEF比賽總結

做了4題,ABCE。感覺不是很滿意。1、D題題意讀不懂,剛開始想法對了,但是可惜題意讀錯了一直WA。2、F題沒來得及看。

感覺本場比賽的題目還算可以。

A:三行系列。讀懂題意就能做。因為只除去了中間的部分。但是感覺放在div3的A題還是稍微難了點。

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=200010;
int n,m,k,v;
int a[maxn],sum[maxn];
int c[maxn];
int ans,ct,cnt,tmp,flag;
char s[maxn];
int main()
{
    int T,cas=1;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d%d",&n,&m,&k,&v);
        ans=n/m;
        tmp=v/m-(k-1)/m;
        printf("%d\n",ans-tmp);
    }
    return 0;
}

 

B:感覺這題有點坑。給你一01序列,長度為n,再給你r,1的地方可以種灑水器,範圍是(pos-r+1,pos+r-1)。pos是為1的位置。

問你至少種多少灑水器可以覆蓋1~n。如果不能輸出-1。直接模擬即可。不過細節挺多,樣例給的還算好。注意-1。

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=200010;
int n,m,k,v;
int a[maxn],sum[maxn];
int c[maxn];
int ans,ct,cnt,tmp,flag;
char s[maxn];
int main()
{
    int T,cas=1;
    scanf("%d%d",&n,&m);
    ans=-1;
    for(int i=1;i<=n;i++)
    {scanf("%d",&a[i]);if(a[i])ans=0;}
    int r=0;
    int i=1;
    while(i<=n)
    {
        int tmp=ans,fg=0;
        for(;i<=n;i++)
        if(a[i]&&i-m+1<=r+1){fg=i;}
        else if(a[i]&&i-m+1>r+1) break;
        if(fg) ans++;
        r=fg+m-1;
        i=fg+1;
        if(r>=n) break;
        if(!fg) {ans=-1;break;}

    }
    printf("%d\n",ans);
    return 0;
}

C:有一個書架(只有一層),m次操作,每次操作為 一個字元+x  如果字元為'L'或'R',則放上編號為x的書。放在最左邊或最右邊。如果是'?' x 則查詢至少移除多少本書才能使編號為x的書位於最左邊或最右邊。

不知道別人思路怎麼樣,我的第一感覺就是樹狀陣列。從中間分開,200005和200006開始分別往左右放,詢問的時候查詢啷個值比較一下就行了。

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=400010;
int n,m,k,v;
int a[maxn],mp[maxn];
int c[maxn];
int ans,ct,cnt,tmp,flag;
char s[maxn];
int lb(int x){return x&(-x);}
void add(int i,int v)
{
    while(i<maxn)
    {
        c[i]+=v;
        i+=lb(i);
    }
}
int query(int i)
{
    int ans=0;
    while(i>0)
    {
        ans+=c[i];
        i-=lb(i);
    }
    return ans;
}
int main()
{
    int T,cas=1;
    scanf("%d",&n);
    memset(c,0,sizeof(c));
    int l=200005,r=200006;
    for(int i=0;i<n;i++)
    {
        scanf("%s %d",s,&m);
        if(s[0]=='L') {mp[m]=l--;add(l+1,1);}
        else if(s[0]=='R') {mp[m]=r++;add(r-1,1);}
        else
        {
            ans=min(query(mp[m]-1),query(400008)-query(mp[m]));
            printf("%d\n",ans);
        }
    }
      //  if(flag) puts("Yes"); else puts("No");
    return 0;
}

D:這題題意很迷啊。我感覺題意說的有問題。實際上就是給你n個玩具,m個箱子,每個箱子容量為k,每個玩具體積為a[i]。

從第一個玩具開始依次裝,如果能把所有玩具裝進去就停止。否則到了一個玩具,已經沒有足夠的箱子容量裝了的話,他就會把現在所有箱子裡最早裝的玩具扔掉。直到當前玩具能裝進去。問最後箱子裡一共能裝多少玩具。

思路:如果題意像我說的這麼簡單,那麼這道題就可以當做A題了(然而出題人非要整的花裡胡哨亂七八糟看不懂的)。顯然只需要從後往前貪心裝,裝不下就停。這時裝的玩具數量就是答案。

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=400010;
ll n,m,k,v;
ll a[maxn],sum[maxn];
ll c[maxn],ed[maxn],be[maxn];
ll ans,ct,cnt,tmp,flag;
char s[maxn];
int main()
{
    int T,cas=1;
    scanf("%lld%lld%lld",&n,&m,&k);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
    }
    for(int i=0;i<=max(2*n,2*m);i++)
    c[i]=k;
    int box=0,l=1,ans=0,tmp=0,st=0,aa=0;
    for(int i=n;i>=1;i--)
    {
        if(c[box]>=a[i])
        {
            c[box]-=a[i];
            be[i]=box;
            tmp++;
            ans=max(ans,tmp);
        }
        else if(box+1<m)
        {
            box++;
            c[box]-=a[i];
            be[i]=box;
            tmp++;
            ans=max(ans,tmp);
        }
        else break;
    }
    printf("%d\n",ans);
      //  if(flag) puts("Yes"); else puts("No");
    return 0;
}

E:

給你兩個二進位制01串,長度分別為n,m(n,m<=2e5)。求第一個串&第二個串的十進位制和。每&一次,就去掉第二個串的最後一位繼續&,直到第二個串為空。

觀察可以發現,只需要維護一個2的n次方的字首和就行了。m>n時,第二個串的前m-n位一定是每一個1都會與第一個串每一個1&一次,後面的n位就依次往後了。m<n時,第二個串每個1就只有機會&第一個串中後n-m個1了。可以畫圖理解一下。(題意說清楚就比D題簡單了)

我用的快速冪,其實可以不用的,不用就可以O(n)解決。

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=400010;
const ll mo=998244353;
ll n,m,k,v;
ll a[maxn],sum[maxn];
ll c[maxn],ed[maxn],be[maxn];
ll ans,ct,cnt,tmp,flag;
char s[maxn],t[maxn];
ll power(ll a,ll n)   //a的n次方mod
{
    ll ans=1;
    a=a%mo;
    while (n)
    {
        if(n&1) ans=(ans*a)%mo;
        n>>=1;
        a=(a*a)%mo;
        }
    return ans;
}
int main()
{
    int T,cas=1;
    scanf("%lld%lld",&n,&m);
    scanf("%s%s",s,t);
    sum[n+1]=0;ans=0;
    for(int i=n-1;i>=0;i--)
    {
        if(s[i]=='0') sum[i]=sum[i+1];
        else sum[i]=(sum[i+1]+power(2,n-i-1))%mo;
    }
    if(m>n)
    {
        for(int i=0;i<m-n;i++)
        if(t[i]=='1'){
        ans=(ans+sum[0])%mo;
        }
        for(int i=m-n,j=0;i<m;i++,j++)
        if(t[i]=='1'){
        ans=(ans+sum[j])%mo;
        }
    }
    else
    {
        for(int i=0,j=n-m;i<m;i++,j++)
        if(t[i]=='1'){
        ans=(ans+sum[j])%mo;
        }
    }

    printf("%lld\n",ans);
      //  if(flag) puts("Yes"); else puts("No");
    return 0;
}

F:(這道題在區域賽上可能算個簽到題吧。。。)

給你二維平面的n個點(n<=2e5) 以每個點的max(x,y)分層,你從(0,0)點開始走,每一步只能走上下左右長度為1,你要先走到第一層,走過第一層的所有點後,才能走第二層,以此類推,求走完最後一層的所有點,最少需要多少步。

由於要分層,就用一個vector存一下每一層的點。觀察發現每一層最左上的點到最右下的點,一定有一條路徑可以經過這一層的所有點。顯然這就是走遍這一層最短步數路線。於是每一層的點,按x從小到大排序,x相同按y從大到小排序。畫個圖一下就懂了。於是dp方程也有了。設dp[i][0]為走完第i層且位於這一層的最左上的點的最少步數。則v[i][]表示第i層的所有點(排序後的)

t1和t2為離散化後第i-1和第i層的點的編號。於是有

dp[i][0]=min(dp[i-1][1]+dist(v[t1].back(),v[t2].back()),dp[i-1][0]+dist(v[t1][0],v[t2].back()))+dist(v[t2][0],v[t2].back());

同樣,設dp[i][1]為走完第i層且位於這一層的最右下的點的最少步數。則有

dp[i][1]=min(dp[i-1][1]+dist(v[t1].back(),v[t2][0]), dp[i-1][0]+dist(v[t1][0],v[t2][0]))+dist(v[t2][0],v[t2].back());

最後min(dp[最後一層][0],dp[最後一層][1])就是答案。

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f3f3f3f3fLL
using namespace std;
const int maxn=1e6+10;
map<int,int>mp;
int cnt,n;
vector<pair<ll,ll> >v[maxn];
ll dp[maxn][2];
ll dist(pair<ll,ll> a,pair<ll,ll> b)
{
    return abs(a.first-b.first)+abs(a.second-b.second);
}
bool cmp(pair<ll,ll> a,pair<ll,ll> b)
{
    return a.first<b.first||(a.first==b.first&&a.second>b.second);
}
int main()
{
    scanf("%d",&n);
    vector<ll>vv;
    cnt=0;
    for(int i=1;i<=n;i++)
    {
        ll l,r;
        scanf("%lld%lld",&l,&r);
        ll c=max(l,r);
        if(mp[c]==0)
        {
            mp[c]=++cnt;
            vv.push_back(c);
        }
        v[mp[c]].push_back(make_pair(l,r));
    }
    vv.push_back(0);
    mp[0]=++cnt;
    v[cnt].push_back(make_pair(0,0));
    sort(vv.begin(),vv.end());
    for(int i=0;i<vv.size();i++)
    dp[i][0]=dp[i][1]=inf;
    dp[0][0]=dp[0][1]=0;
    for(int i=1;i<vv.size();i++)
    {
        int t1=mp[vv[i-1]];
        int t2=mp[vv[i]];
        sort(v[t2].begin(),v[t2].end(),cmp);
        dp[i][0]=min(dp[i-1][1]+dist(v[t1].back(),v[t2].back()),
                     dp[i-1][0]+dist(v[t1][0],v[t2].back()));
        dp[i][0]+=dist(v[t2][0],v[t2].back());

        dp[i][1]=min(dp[i-1][1]+dist(v[t1].back(),v[t2][0]),
                     dp[i-1][0]+dist(v[t1][0],v[t2][0]));
        dp[i][1]+=dist(v[t2][0],v[t2].back());
    }
    printf("%lld\n",min(dp[vv.size()-1][0],dp[vv.size()-1][1]));
}