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;
}