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;
}
本文解析了Codeforces平台上的两个经典编程题:一是通过字符串匹配寻找最大数量的不重叠子串;二是利用二分加贪心算法解决搬运箱子问题,以达到最短时间内的最优解。
1801

被折叠的 条评论
为什么被折叠?



