暑假的第一次測試(一)

A題 ZgukistringZ( 原題 codeforces Round # 307 Div.2 B)

一般的字符串模擬題。題目的大致意思是有字符串a、b、c。將a的某些字母進行交換,問a的不重疊子串和b、c相同的最多次數。

比如樣例三:

a串:abbbaaccca

b串:ab

c串:aca

將a變成ababacabcc,相同的有ab、ab、aca三個不重疊子串,注意題目說明是不重疊。

然後我覺得是一個模擬題,將a串中的所有字母進行個數統計,b、c串的也分別進行統計。然後可以先算出如果用a串只去構成b串最多有多少串,設爲x;之後就枚舉構成b串的數目,將a串的字母個數減去b串的對應字母個數*b串的個數,剩下的字母能構成多少個c串,然後求個max並記錄此時的b串和c串數目。

之後只要輸出b串、c串,最後再輸出剩餘的字母。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int min(int a,int b)
{
    if (a<b) return a; else return b;
}
int la,lb,lc,i,j,x,num,num2,d1,d2,maxn;
char sa[100012],sb[100012],sc[100012];
int pa[26],pb[26],pc[26],b[26];
int main()
{
    scanf("%s",sa); la=strlen(sa);
    scanf("%s",sb); lb=strlen(sb);
    scanf("%s",sc); lc=strlen(sc);
    memset(pa,0,sizeof(pa));
    memset(pb,0,sizeof(pb));
    memset(pc,0,sizeof(pc));
    for (i=0;i<la;i++)
        pa[sa[i]-'a']++;

    for (i=0;i<lb;i++)
        pb[sb[i]-'a']++;

    for (i=0;i<lc;i++)
        pc[sc[i]-'a']++;
    num=-1;
    for (i=0;i<=25;i++)
    if (pb[i]!=0)
    {
       if (num!=-1) num=min(num,pa[i]/pb[i]);
       else num=pa[i]/pb[i];
    }
    for (i=0;i<=num;i++)
    {
        for (j=0;j<=25;j++)
            b[j]=pa[j]-pb[j]*i;
        num2=-1;
        for (j=0;j<=25;j++)
            if (pc[j]!=0)
            if (num2!=-1) num2=min(num2,b[j]/pc[j]);
            else num2=b[j]/pc[j];
        if (i+num2>maxn)
        {
            maxn=i+num2;
            d1=i; d2=num2;
        }
    }
    for (i=1;i<=d1;i++)
    cout<<sb;
    for (i=1;i<=d2;i++)
    cout<<sc;
    for (i=0;i<=25;i++)
    {
        x=pa[i]-(pb[i]*d1+pc[i]*d2);
        for (j=1;j<=x;j++)
            cout<<char(97+i);
    }
    cout<<endl;
    return 0;
}

B題 GukiZ hates Boxes(原題codeforces 511 C)

大致意思是有m個學生要在最短時間內要搬完所有堵在路上的箱子,每一秒學生可以在兩件事中任選一件:

1、搬他所在位置的一個箱子

2、向前移動一格

所有人一開始都在0的位置,要在最短時間內搬完箱子,求最短時間。

這題是一個二分加貪心,二分時間,最短設爲最遠的那個箱子的位置,最長設爲n+1+所有箱子的個數/m。

之後就是貪心,當前假設時間爲t,看是否可行。我們可以從最後一個有箱子的格子開始,要走到最後一個有箱子的格子需要t1時間,那走到那一格還剩餘 t - t1 的時間,可以用那些剩餘時間搬當前格子上的箱子,如果時間有剩餘,可以搬取前面格子中的箱子,相當於先搬了前面的箱子然後走到後面搬後面的箱子。依次往前搬,詳情見代碼註釋。

#include<iostream>
using namespace std;
const int MAXN=100012;
int n,m;
long long int a[MAXN],b[MAXN];
int doit(long long int mid)//計算mid這個時間是否可行
{
    int i,j;
    long long int x,y,m1;
    i=n; //當前格子,從後往前做
    m1=m;//m1爲可用人數
    for (j=1;j<=n;j++) b[j]=a[j];//另建數組方便計算
    while (i>0)
    {
        while (i>0&&b[i]==0) i--; //如果格子爲空,往前計算
        if (i==0) return 1;//如果格子都爲空,即可行,返回
        x=mid-i; //x爲到這個格子還剩餘的時間
        if (x<=0) return 0; //如果到這個格子時間已經小於等於0,但這個格子上還有箱子,不可行,返回
        m1-=b[i]/x; 總人//減去用剩餘時間去搬這個格子上的箱子,並把時間都用完的人  
        if (m1<0) return 0; //如果人數已經小於0,說明搬不玩,不可行,返回
        if (b[i] % x==0) b[i]=0;//當前這個格子的箱子搬完了
        else if (b[i] % x!=0) //還沒搬完
        {
            m1--; //要再用一個人
            if (m1<0) return 0;//如果人數已經小於0,說明搬不玩,不可行,返回
            y=x-(b[i] % x);//此人搬完這個格子還剩餘的時間,說明他前面可以再搬點箱子,再往後走
            b[i]=0;//當前箱子搬完
            while (y>0)
            {
                while (i>0&&b[i]==0) i--;
                if (i==0) return 1;
                if (y>=b[i]) { y-=b[i]; b[i]=0; }//如果時間比當前箱子數目多,可以搬完當前的箱子,還可以搬前面的
                else { b[i]-=y; y=0;  } //時間用完了
            }
        }
        if (m1==0) break;//人數用完
    }
    while (i>0&&b[i]==0) i--;
    if (i>0) return 0;//沒搬完,不可行
    return 1;//搬完了,可行
}
int main()
{
    int i;
    long long int sum,l,r,mid;
    sum=0;
    cin>>n>>m; a[0]=0;
    for (i=1;i<=n;i++)
    {
        cin>>a[i];
        sum+=a[i];
    }
    l=0; r=n+sum;//l和r可以往兩邊取,反正二分很快0.0
    while (l<r)
    {
        mid=(r+l)/2;
        if (doit(mid)) r=mid; else l=mid+1;
    }
    cout<<r<<endl;
    return 0;
}



發佈了36 篇原創文章 · 獲贊 3 · 訪問量 8144
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章