还好没在线打,这场属实搞心态。
题目:A. Acacius and String
题意:构成一个字符串中只有一个abacaba的子串,?可以随意填。
枚举?所构成的是子串abacaba的第几位,之后在遍历整个串是否只有一个,不成立还原继续。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define inf 0x3f3f3f3f
#define llinf 0x3f3f3f3f3f3f3f3f
#define MAX_len 200005*4
using namespace std;
typedef long long ll;
typedef pair<int,int> PP;
const int mod=1e9+7;
const int MAXlen=2e5+10;
double eps=1e-4;
char s[66];
char hh[66]="abacaba";
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,i,j;
scanf("%d",&n);
scanf("%s",s+1);
int sum=0;
for(i=1;i<=n;i++)
{
if(s[i]=='a')
{
int len=1;
for(j=i+1;j<=n&&len<=6;j++)
{
if(s[j]==hh[len])
{
len++;
continue;
}
else
break;
}
if(len==7)
{
sum++;
}
}
}
if(sum==1)
{
printf("YES\n");
for(i=1;i<=n;i++)
{
if(s[i]=='?')
{
printf("z");
continue;
}
printf("%c",s[i]);
}
printf("\n");
continue;
}
if(sum>1)
{
printf("NO\n");
continue;
}
bool bo=false;
for(i=1;i<=n;i++)
{
if(s[i]=='?')
{
bool op=false,flag=false;
for(j=0;j<=6;j++)
{
if(i-j>=1&&(i+6-j<=n))
{
char temp[10];
int len=0;
op=true;
flag=false;
for(int k=i-j;k<=i+6-j;k++)
temp[len++]=s[k];
len=0;
for(int k=i-j;k<=i+6-j;k++)
{
if(s[k]=='?')
{
s[k]=hh[len++];
continue;
}
if(s[k]!=hh[len])
{
op=false;
break;
}
len++;
}
if(!op)
{
len=0;
for(int k=i-j;k<=i+6-j;k++)
s[k]=temp[len++];
continue;
}
int cnt=0;
for(int k=1;k<=n;k++)
{
if(s[k]=='a')
{
int llen=1;
for(int kk=k+1;kk<=n&&llen<=6;kk++)
{
if(s[kk]==hh[llen])
{
llen++;
continue;
}
else
break;
}
if(llen==7)
{
cnt++;
}
}
}
if(cnt==1)
{
flag=true;
break;
}
len=0;
for(int k=i-j;k<=i+6-j;k++)
s[k]=temp[len++];
}
}
if(op&&flag)
{
bo=true;
break;
}
}
}
if(bo)
{
printf("YES\n");
for(i=1;i<=n;i++)
{
if(s[i]=='?')
{
printf("z");
continue;
}
printf("%c",s[i]);
}
printf("\n");
}
else
printf("NO\n");
}
return 0;
}
题目:B. Dubious Cyrpto
题意:给定l,r,m,在[l,r]内找到a,b,c, n ∗ a + b − c = m n*a+b−c=m n∗a+b−c=m,n为任意正整数。
枚举a,m%a,判断b-c范围一定在[l-r,r-l]中。当a>m时一种情况,之后取余,以及判断b-c为负数的情况别漏了。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define inf 0x3f3f3f3f
#define llinf 0x3f3f3f3f3f3f3f3f
#define MAX_len 200005*4
using namespace std;
typedef long long ll;
typedef pair<int,int> PP;
const int mod=1e9+7;
const int MAXlen=2e5+10;
double eps=1e-4;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
ll i,j,l,r,m;
scanf("%lld %lld %lld",&l,&r,&m);
for(i=l;i<=r;i++)
{
if(m<i)
{
if(l<=(r-i+m))
{
printf("%lld %lld %lld\n",i,r-i+m,r);
break;
}
continue;
}
ll temp2=m%i;
if(temp2+l<=r)
{
printf("%lld %lld %lld\n",i,l+temp2,l);
break;
}
ll temp1=(m/i+1)*i-m;
if(l+temp1<=r)
{
printf("%lld %lld %lld\n",i,r-temp1,r);
break;
}
}
}
return 0;
}
题目:C. Choosing flowers
题意:有m种花(每种无限数量),送n朵花,第一次收到的就加a[i],之后的都是b[i],问值最大。
一开始分析的是找到最大的b[i],筛掉大于b[i]的a[i],剩下的全部都拿b[i],仔细分析显然是错的,考虑不到所有的情况,有可能拿第二大的b[i]。可以发现,我们肯定要确定拿一种花我们之后全是拿他是主要的花。枚举主要拿的是第几种,a[i]用前缀和,加二分把大于b[i]的a[i]拿掉,每种情况都考虑维护一个最大值。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define inf 0x3f3f3f3f
#define llinf 0x3f3f3f3f3f3f3f3f
#define MAX_len 200005*4
using namespace std;
typedef long long ll;
typedef pair<int,int> PP;
const int mod=1e9+7;
const int MAXlen=2e5+10;
double eps=1e-4;
ll a[100010],b[100010];
ll c[100010];
ll sum[100010];
struct RatioComp
{
bool operator()(const pair<int, int>& A, const pair<int, int>& B)
{
return A.first>B.first;
}
};
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
// multiset,RatioComp>hh;
ll n,m,i,j;
scanf("%lld %lld",&n,&m);
ll MAX=0;
for(i=1;i<=m;i++)
{
scanf("%lld %lld",&a[i],&b[i]);
c[i]=a[i];
MAX=max(b[i],MAX);
}
sum[0]=c[0]=0;
sort(c+1,c+1+m);
for(i=1;i<=m;i++)
sum[i]=sum[i-1]+c[i];
ll ans=c[m];
sum[m+1]=0;
for(i=1;i<=m;i++)
{
int pos=upper_bound(c,c+1+m,b[i])-c;
if(pos>m)
{
ans=max(ans,(n-1)*b[i]+a[i]);
continue;
}
if(!pos)
{
if(n<=m)
{
ans=max(ans,sum[m]-sum[m-n]);
}
else
{
ll temp=sum[m]+(n-m)*MAX;
ans=max(ans,temp);
}
continue;
}
if(m-pos+1>=n)
{
ans=max(ans,sum[m]-sum[m-n]);
continue;
}
ll cnt=n-(m-pos+1);
ll num=sum[m]-sum[pos-1];
if(a[i]>b[i])
num+=cnt*b[i];
else
num+=(cnt-1)*b[i]+a[i];
ans=max(ans,num);
}
printf("%lld\n",ans);
}
return 0;
}
题目:D. New Passenger Trams
题意:一天h小时,一小时m分钟(偶数),有客车和货车客车需要提前k分钟空出时间上下车,如果货车在这个时间段则要删除,(不包括端点,端点的货车不需要删除),客车每半小时发一辆,问最小删除的货车数以及客车最好的发车时间。(第一列发车时间t一定在0–m/2)内。
可以发现和h无关,我们只需要考虑m,因为每半小时就发一辆,(t-k,t)…(t-k+m/2,t+m/2)…。仔细考虑如果在某一时刻是最优的情况,那么在这个圆上是可以移动的,整个的发车时间跟着移动,一旦有一个发车时间与货车的发车时间重叠就不能移动了。那么我们找到了枚举的方向,枚举n辆货车的发车时间与客车的端点重合的情况,m范围太大是不能枚举的。我们预处理出每辆货车在半小时内的情况,排序就可以二分了。具体见代码。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define inf 0x3f3f3f3f
#define llinf 0x3f3f3f3f3f3f3f3f
#define MAX_len 200005*4
using namespace std;
typedef long long ll;
typedef pair<int,int> PP;
const int mod=1e9+7;
const int MAXlen=2e5+10;
double eps=1e-4;
vector<ll>hh;
vector<ll>sorted;
int main()
{
ll n,m,i,j,h,k;
scanf("%lld %lld %lld %lld",&n,&h,&m,&k);
for(i=0;i<n;i++)
{
ll xx,yy;
scanf("%lld %lld",&xx,&yy);
hh.push_back((xx*m+yy)%(m/2));
sorted.push_back(hh[i]);
}
sort(sorted.begin(),sorted.end());
ll ans=llinf;
ll bestt=0;
for(i=0;i<sorted.size();i++)
{
if(sorted[i]+k<m/2)
{
j=lower_bound(sorted.begin(),sorted.end(),sorted[i]+k)-sorted.begin();
ll cnt=j-i-1;
if(cnt<ans)
{
ans=cnt;
bestt=sorted[i];
}
}
else
{
j=lower_bound(sorted.begin(),sorted.end(),sorted[i]+k-m/2)-sorted.begin();
ll cnt=(int)sorted.size()-i+j-1;
if(cnt<ans)
{
ans=cnt;
bestt=sorted[i];
}
}
}
printf("%lld %lld\n",ans,(bestt+k)%(m/2));
ll t=bestt;
for(j=0;j<hh.size();j++)
{
ll x=hh[j];
if(t+k>m/2)
{
if(x>t||x<t+k-m/2)
{
printf("%lld ",j+1);
}
}
else
{
if(x>t&&x<t+k)
{
printf("%lld ",j+1);
}
}
}
return 0;
}