『模拟赛』CSP-S加赛1
Rank
一般
A. 小W与伙伴招募
仔细想了想,发现是贪心题。
赛时想了跟正解完全有些不太一样的做法,被顶针说假了,但其实开了 long long
能有 80pts。后来发现如果思路正确打 \(\mathcal{O(nm)}\) 的暴力能有 95pts。
《对于 60% 的数据》
考虑正解的贪法,每天相当于将第 \(i\) 宝石进货 \(b_i\) 个,维护一下每种宝石当前库存,然后从小到大买即可,这样也就有了上面 \(\mathcal{O(nm)}\) 的做法。要想过最后一个点,我们可以考虑输出前缀和 我们考虑用线段树来维护这个库存,线段树上二分来解决查询,这样就做到了 \(\mathcal{O(n\log m+m)}\) 的复杂度。还有一种单调栈优化的,能达到 \(\mathcal{O(n)}\),比较牛。
点击查看代码
#include<bits/stdc++.h>
#define fo(x,y,z) for(register ll (x)((y));(x)<=(z);(x)++)
#define fu(x,y,z) for(register ll (x)((y));(x)>=(z);(x)--)
using namespace std;
typedef __int128 ll;
#define lx ll
inline lx qr()
{
char ch=getchar();lx x=0,f=1;
for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+(ch^48);
return x*f;
}
#undef lx
#define qr qr()
const int Ratio=0;
const int N=2e5+5;
const int mod=1e9+9;
int n,m;
int c[N];
long long ans;
ll numb[N],sumcos[N];
ll num[N<<2],sum[N<<2],tag[N<<2],cle[N<<2];
struct rmm
{
ll a,b;
}b[N];
bool cmp(rmm A,rmm B)
{
if(A.a!=B.a) return A.a<B.a;
return A.b>B.b;
}
namespace Wisadel
{
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid ((l+r)>>1)
void Wpushup(int rt)
{
num[rt]=num[ls]+num[rs];
sum[rt]=sum[ls]+sum[rs];
}
void Wpushdown(int rt,int l,int r)
{
num[ls]+=tag[rt]*(numb[mid]-numb[l-1]);
num[rs]+=tag[rt]*(numb[r]-numb[mid]);
sum[ls]+=tag[rt]*(sumcos[mid]-sumcos[l-1]);
sum[rs]+=tag[rt]*(sumcos[r]-sumcos[mid]);
tag[ls]+=tag[rt],tag[rs]+=tag[rt];
tag[rt]=0;
}
void Wclerr(int rt)
{
num[ls]=num[rs]=0;
sum[ls]=sum[rs]=0;
cle[ls]=cle[rs]=1;
tag[ls]=tag[rs]=0;
cle[rt]=0;
}
void Wupd(int rt,int l,int r,int k)
{
if(k>0)
{
num[rt]+=numb[r]-numb[l-1];
sum[rt]+=sumcos[r]-sumcos[l-1];
tag[rt]++;
}
else
{
num[rt]=sum[rt]=tag[rt]=0;
cle[rt]=1;
}
}
ll Wq(int rt,int l,int r,int k)
{
if(l==r)
{
num[rt]-=k,sum[rt]-=b[l].a*k;
return b[l].a*k;
}
if(cle[rt]) Wclerr(rt);
if(tag[rt]) Wpushdown(rt,l,r);
ll res=0;
if(k<=num[ls])
{
res+=Wq(ls,l,mid,k);
Wpushup(rt);
return res;
}
res+=sum[ls]+Wq(rs,mid+1,r,k-num[ls]);
Wupd(ls,l,mid,-1);
Wpushup(rt);
return res;
}
short main()
{
freopen("a.in","r",stdin),freopen("a.out","w",stdout);
n=qr,m=qr;
fo(i,1,n) c[i]=qr;
fo(i,1,m) b[i].a=qr,b[i].b=qr,b[i].b=(b[i].b==-1?1e12:b[i].b);
sort(b+1,b+1+m,cmp);
fo(i,1,m)
{
numb[i]=numb[i-1]+b[i].b;
sumcos[i]=sumcos[i-1]+1ll*b[i].a*b[i].b;
if(b[i].b==1e12){m=i;break;}
}
fo(i,1,n) Wupd(1,1,m,1),ans+=Wq(1,1,m,c[i]);
printf("%lld\n",ans);
return Ratio;
}
}
int main(){return Wisadel::main();}
B. 小W与制胡串谜题
签,但想复杂了所以没签上。
一个排序就解决了,不过看到第二个样例发现直接比较不太行,像 bca
和 bc
,于是我就想到了如果存在前缀关系,判断长串后缀与短串的大小,然后由于不清楚 cmp 的比较关系返回值导致搞错了只有 55pts。实际上比较 \(a+b\lt b+a\) 就行了。
点击查看代码
#include<bits/stdc++.h>
#define fo(x,y,z) for(register int (x)((y));(x)<=(z);(x)++)
#define fu(x,y,z) for(register int (x)((y));(x)>=(z);(x)--)
using namespace std;
typedef long long ll;
#define lx int
inline lx qr()
{
char ch=getchar();lx x=0,f=1;
for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+(ch^48);
return x*f;
}
#undef lx
#define qr qr()
const int Ratio=0;
const int N=5e5+5;
const int mod=1e9+9;
int n;
string s[N];
bool cmp(string s1,string s2){return string(s1+s2)<string(s2+s1);}
namespace Wisadel
{
short main()
{
freopen("a.in","r",stdin),freopen("a.out","w",stdout);
n=qr;
fo(i,1,n) cin>>s[i];
sort(s+1,s+1+n,cmp);
fo(i,1,n) cout<<s[i];
return Ratio;
}
}
int main(){return Wisadel::main();}
C. 小W与屠龙游戏
由于之前学过博弈论所以看出来了是 Nim Game 的变种,因为当时不会线性基就没看 Nim-k 的实现,后面补上。
末
突然的考试,有点慌其实。
此 W 非彼 W,差评
打到 1.5h 左右觉得 200pts 是大众分,于是开始被 T3 折磨,想到结束也没想出点啥,感觉学东西学一半就很难受。
看来大家都挂了不少分,致敬大黄首次不挂分反向挂分模拟赛!
完结撒花~