比赛地址:https://codeforces.com/contest/1555。
只有 ABCDE 的题解,F 不会。
A
设用了 \(x\) 个小份,\(y\) 个中份,\(z\) 个大份,那么我们要使得 \(6x+8y+10z\ge n\),并让 \(15x+20y+25z\) 最小。
这里有一个很好的性质:\(15x+20y+25z=\frac 52(6x+8y+10z)\)。所以只需最小化 \(6x+8y+10z\)。
而 \(6x+8y+10z\) 可以取遍 \(\ge 6\) 的所有偶数,然后就做完了。
typedef long long ll;
void mian(){
ll n;scanf("%lld",&n);
if(n<=6)n=6;
else if(n&1)n++;
printf("%lld\n",n/2*5);
}
B
显然最好的办法是竖着或者横着移。分 \(4\) 类(往左移,往右移,往上移,往下移)讨论即可。
typedef long long ll;
inline int dis(int a,int b){
return std::max(b-a,0);
}
void mian(){
int w,h,x1,y1,x2,y2,w2,h2;
scanf("%d%d%d%d%d%d%d%d",&w,&h,&x1,&y1,&x2,&y2,&w2,&h2);
int w1=x2-x1,h1=y2-y1;
if(w1+w2>w&&h1+h2>h)puts("-1");
else{
int ans=0x3f3f3f3f;
bool okw=(w1+w2<=w),okh=(h1+h2<=h);
if(okw)ans=std::min(ans,std::min(dis(x1,w2),dis(w-w2,x2)));
if(okh)ans=std::min(ans,std::min(dis(y1,h2),dis(h-h2,y2)));
printf("%d\n",ans);
}
}
C
Alice 的走法只有 \(n\) 种情况,于是考虑枚举这 \(n\) 种情况。
Alice 走完后,剩下的有硬币的格子是第一行的一个后缀和第二行的一个前缀。Bob 要么就都取第一行的这个后缀,要么就都取第二行的这个前缀。
typedef long long ll;
const int N=1e5;
int n,a[2][N+10],sum1[2][N+10],sum2[2][N+10];
void mian(){
for(int i=1;i<=n;i++)a[0][i]=sum1[0][i]=a[1][i]=sum1[1][i]=sum2[0][i]=sum2[1][i]=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[0][i]);
for(int i=1;i<=n;i++)
scanf("%d",&a[1][i]);
for(int i=1;i<=n;i++){
sum1[0][i]=sum1[0][i-1]+a[0][i];
sum1[1][i]=sum1[1][i-1]+a[1][i];
}
for(int i=n;i>=1;i--){
sum2[0][i]=sum2[0][i+1]+a[0][i];
sum2[1][i]=sum2[1][i+1]+a[1][i];
}
int ans=0x3f3f3f3f;
for(int i=1;i<=n;i++)
ans=std::min(ans,std::max(sum1[1][i-1],sum2[0][i+1]));
printf("%d\n",ans);
}
D
美丽的字符串只可能是 \(\texttt{abcabcabc}\cdots\) 的子串或者是 \(\texttt{acbacbacb}\cdots\) 的子串。
每次询问我们把 \(\texttt{abc}\cdots,\texttt{bca}\cdots,\texttt{cab}\cdots,\texttt{acb}\cdots,\texttt{cba}\cdots,\texttt{bac}\cdots\) 这 \(6\) 个串和要询问的串对比一下即可。
可以用前缀和维护一下。(我写了个线段树。。)
typedef long long ll;
const int N=2e5;
/*
* 0 abc
* 1 bca
* 2 cab
*
* 3 acb
* 4 cba
* 5 bac
*/
struct Node{
int val[6],len;
};
Node t[N*4+10];
int n,m;
char s[N+10];
inline int get(int x,int len){
if(0<=x&&x<=2)return (x+len)%3;
x-=3;
return (x+len)%3+3;
}
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
inline Node pushUp(Node L,Node R){
Node res;
for(int i=0;i<6;i++)res.val[i]=L.val[i]+R.val[get(i,L.len)];
res.len=L.len+R.len;
return res;
}
void build(int i,int l,int r){
if(l==r){
if(s[l]=='a')t[i].val[1]=t[i].val[2]=t[i].val[4]=t[i].val[5]=1;
if(s[l]=='b')t[i].val[0]=t[i].val[2]=t[i].val[3]=t[i].val[4]=1;
if(s[l]=='c')t[i].val[0]=t[i].val[1]=t[i].val[3]=t[i].val[5]=1;
t[i].len=1;
return;
}
int mid=(l+r)>>1;
build(ls(i),l,mid);
build(rs(i),mid+1,r);
t[i]=pushUp(t[ls(i)],t[rs(i)]);
}
Node query(int i,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr)return t[i];
int mid=(l+r)>>1;
if(ql>mid) return query(rs(i),mid+1,r,ql,qr);
if(qr<=mid)return query(ls(i),l,mid,ql,qr);
return pushUp(query(ls(i),l,mid,ql,qr),query(rs(i),mid+1,r,ql,qr));
}
#undef ls
#undef rs
void mian(){
scanf("%d%d",&n,&m);
scanf("%s",s+1);
build(1,1,n);
while(m--){
int l,r;scanf("%d%d",&l,&r);
Node res=query(1,1,n,l,r);
int ans=0x3f3f3f3f;
for(int i=0;i<6;i++)
ans=std::min(ans,res.val[i]);
printf("%d\n",ans);
}
}
E
先按 \(w\) 将线段排序。
双指针。边扫边维护 \([1,m-1]\)(为什么要 \(-1\) 一会再解释)中每个点被线段覆盖了多少次,如果覆盖次数的全局 \(\min\) 等于 \(0\),说明有一些点没被覆盖到,还要再往右扫。否则就统计答案。
小细节:所有线段的右端点要 \(-1\)。比如说有两个线段 \([1,3]\) 和 \([4,7]\),他们是没法覆盖 \([1,7]\) 的。
typedef long long ll;
const int N=3e5;
const int M=1e6;
struct Node{
int mn,atag;
};
struct Node2{
int l,r,w;
inline bool operator<(const Node2 &rhs)const{
return w<rhs.w;
}
};
Node t[M*4+10];
int n,m;
Node2 a[N+10];
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
inline void pushUp(int i){
t[i].mn=std::min(t[ls(i)].mn,t[rs(i)].mn);
}
inline void pushA(int i,int atag){
t[i].atag+=atag;
t[i].mn+=atag;
}
inline void pushDown(int i){
if(t[i].atag){
pushA(ls(i),t[i].atag);
pushA(rs(i),t[i].atag);
t[i].atag=0;
}
}
void modify(int i,int l,int r,int ql,int qr,int x){
if(ql<=l&&r<=qr)return pushA(i,x),void();
int mid=(l+r)>>1;
pushDown(i);
if(ql<=mid)modify(ls(i),l,mid,ql,qr,x);
if(qr>mid) modify(rs(i),mid+1,r,ql,qr,x);
pushUp(i);
}
#undef ls
#undef rs
void mian(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].w);
std::sort(a+1,a+n+1);
int l=1,r=1,ans=0x3f3f3f3f;
while(l<=n){
while(r<=n&&t[1].mn==0)modify(1,1,m-1,a[r].l,a[r].r-1,1),r++;
if(t[1].mn>0)ans=std::min(ans,a[r-1].w-a[l].w);
modify(1,1,m-1,a[l].l,a[l].r-1,-1);
l++;
}
printf("%d\n",ans);
}