AtCoder Beginner Contest 308
题意:结构体排序,按 A i A i + B i \frac {A_i}{A_i+B_i} Ai+BiAi 从大到小来排,若相同则按序号较小的在前来排。
重载一下小于号即可。
code:
const int N=2e5+10,mod=998244353;
struct node{
int a,b,id;
bool operator <(const node &t) const{
if(t.a*(a+b)==a*(t.a+t.b)) return id<t.id;
return a*(t.a+t.b)>t.a*(a+b);
}
}a[N];
void work()
{
int n;
cin>>n;
for(int i=1;i<=n;i++){
int x,y;
cin>>x>>y;
a[i]={x,y,i};
}
sort(a+1,a+1+n);
for(int i=1;i<=n;i++) cout<<a[i].id<<" ";
}
题意:给定一个二维字符数组,问是否能够从(1,1)到达(n,m),且经过的路径必须为 “snukesnuke…"(可以不完整) 。
考虑使用bfs,因为题目要求的是路径是否存在,因此我们需要记录一下到当前这个点的距离为多少,然后判断是否合法即可。
code:
string s[N];
int dx[]={0,1,0,-1},dy[]={1,0,-1,0};
int n,m;
string ss="snuke";
bool st[N][N];
int d[N][N];
bool bfs()
{
queue<pii> q;
q.push({0,0});
st[0][0]=1;
while(q.size())
{
auto t=q.front(); q.pop();
if(t.x==n-1&&t.y==m-1){
return 1;
}
for(int i=0;i<4;i++){
int a=t.x+dx[i],b=t.y+dy[i];
int cnt=d[t.x][t.y];
if(a<0||a>=n||b<0||b>=m||s[a][b]!=ss[(cnt+1)%5]||st[a][b]) continue;
q.push({a,b});
st[a][b]=1;
d[a][b]=d[t.x][t.y]+1;
}
}
return 0;
}
void work()
{
cin>>n>>m;
for(int i=0;i<n;i++){
cin>>s[i];
}
if(s[0][0]!='s') {
cout<<"No"<<endl;
return ;
}
if(bfs()) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
题意:给定字符串,只包括"M",“E”,“X”,其值为 a i a_i ai ,问序列中所有 “MEX” 子序列,其mex的值的和是多少。
很经典的一个处理方法,但是我竟然忘了,果然要康复,我们考虑中间字符“E” ,对于每个字符“E” ,我们只要统计它前面有几个“M”,以及它后面有几个“X”,然后计算一下贡献即可。
code:
const int N=3e5+10,mod=998244353;
string s;
int n,m;
int a[N];
int b[N][3],c[N][3];
void work()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
cin>>s;
s=" "+s;
for(int i=n;i>=1;i--){
for(int j=0;j<3;j++){
if(j==a[i]&&s[i]=='X') c[i][j]=c[i+1][j]+1;
else c[i][j]=c[i+1][j];
}
}
for(int i=1;i<=n;i++){
for(int j=0;j<3;j++){
if(j==a[i]&&s[i]=='M') b[i][j]=b[i-1][j]+1;
else b[i][j]=b[i-1][j];
}
}
int ans=0;
for(int i=1;i<=n;i++){
//cout<<c[1][2]<<endl;
if(s[i]=='E'){
for(int j=0;j<3;j++){
for(int k=0;k<3;k++){
for(int l=0;l<4;l++){
if(l!=j&&l!=k&&l!=a[i]) {
ans+=l*b[i][j]*c[i][k];
break;
}
}
}
}
}
}
cout<<ans<<endl;
}
题意:有n个物品,同时你有m张优惠券,但是每张优惠券有限制,即价值超过 L i L_i Li的物品才能使用,然后优惠 D i D_i Di元,保证 D i ≤ L i D_i \leq L_i Di≤Li, 且每个物品最多使用一张优惠券,问买下这n个物品最低需要多少钱。
考虑贪心的策略,即是先选价值较大的还是选价值较小的,容易发现从价值较小的物品选起是正确的,因为后面价值较大的物品不会影响前面的物品,因为优惠劵有限制。相反如果我们先优先选取价值较大的,则可能暂时没有优惠券使用,而后续又出现了优惠券的情况。
因此我们只需对物品按价值从小到大排序,然后对优惠券也排个序,满足条件的优惠券都插入到优先队列中去,然后每次取堆顶的优惠券来计算答案即可。
code:
const int N=2e5+10,mod=998244353;
int n,m;
int a[N];
int v1[N],v2[N];
pii b[N];
void work()
{
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=m;i++){
cin>>b[i].x;
}
for(int i=1;i<=m;i++){
cin>>b[i].y;
}
sort(b+1,b+1+m);
for(int i=1;i<=m;i++){
v1[i]=b[i].x;
v2[i]=b[i].y;
}
int ans=0;
sort(a+1,a+1+n);
priority_queue<int> q;
for(int i=1,j=1;i<=n;i++){
while(v1[j]<=a[i]&&j<=m){
q.push(v2[j]);
j++;
}
if(q.size()){
ans-=q.top();
q.pop();
}
}
for(int i=1;i<=n;i++) ans+=a[i];
cout<<ans<<endl;
}