前面的碎碎念:
菜鸡不敢打这个比赛,赛后看题解有“水题”就补了题。
戳我传送

A、勇者比武

大意:
H * W的格子上放了J,O,I三种字符,求满足条件(i,j,k,l)的四元组的数量,(i,j)上是J,(i,l)上是O,(k,j)上是I。其中l大于j,k大于i,也就是说问有多少JOI的组合满足O在J的右边,I在J的下边。

思路:

前缀和变形一下,从行末和列末往前计算当前位置右边出现了多少O下面出现了多少I,这个位置如果出现了J,那么这个J的贡献就是两个集合的组合数,将全部J的贡献求和就是结果了,复杂度图片说明 (m*n)。

Code;

#include<bits/stdc++.h>
using namespace std;
const int maxn=3005;
int read(){
    int x=0;char ch=getchar();
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    return x;
}
char a[maxn][maxn];
long long u[maxn][maxn],v[maxn][maxn];
int main() {
    int h=read(),w=read();
    for(int i=1;i<=h;++i)    scanf("%s",a[i]+1);
    for(int i=1;i<=h;++i)
    for(int j=w;j;--j) {
        u[i][j]+=u[i][j+1];
        if(a[i][j]=='O') ++u[i][j];
    }
    for(int j=1;j<=w;++j)
    for(int i=h;i;--i) {
        v[i][j]+=v[i+1][j];
        if(a[i][j]=='I') ++v[i][j];
    }
    long long ans=0;
    for(int i=1;i<=h;++i)
    for(int j=1;j<=w;++j) if(a[i][j]=='J')
        ans+=u[i][j]*v[i][j];
    cout<<ans<<endl;
}

B、画展:

题目大意:
考虑到美观,右边的画框不小于左边的,右边的画不能没左边的好看。

思路:

我们可以用贪心的策略。其实左边和右边不重要,选好后左右颠倒就可以了,题目就变为:左边的框大于等于右边的,左边的框不能没有右边好看。先选择装好看的,如果都好看,就先装体积大的,接下来就可以贪心的用最大的框去装剩下的画中最好看的,如果装不下就换过一副画。复杂度图片说明 (NlogN+MlogM).
可以试着先装美观最小的,如果美观一样先装最小的,然后贪心的用最小的框框去装剩下的框中美观最小的,装不下就换一个框,但是这样很有可能会浪费几个框,比如后面可能有更好看的画还更小,且能装下这个画框,从而后面的结果也可能会比不要这个框的结果要大。如果倒叙遇到当前美度的画放不下当前的画框,我们试着不要这副画,如果要这幅画而是不要这个框会不会更有更优的结果(肯定没有!这个框都要不起后面就没有要得起的了,把前面已经装了画的画框拆下来装这个的结果显然是一样的,这就是拆东墙补西墙,随便前i幅画和前j个框怎么配对,只要符合条件,对后面是没有影响的)。所以我们选择倒序去贪心。

Code:

#include<bits/stdc++.h>
using namespace std;
int read(){
    int x=0;char ch=getchar();
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    return x;
}
void print(int x){
    if(x>=10) print(x/10);
    putchar(x%10+'0');
}
const int maxn=1e5+5;
struct node{
    int v,val;
    bool operator<(const node&a) const {
        if(val==a.val)    return v>a.v;
        return val>a.val;
    }
}a[maxn];
int b[maxn];
int main() {
    int n=read(),m=read();
    for(int i=1;i<=n;++i)    a[i].v=read(),a[i].val=read();
    for(int i=1;i<=m;++i)    b[i]=read();
    sort(a+1,a+1+n);
    sort(b+1,b+1+m,[](int a,int b){
        return a>b;
    });
    int cnt=0;
    for(int i=1,j=1;i<=n&&j<=m;++i) if(b[j]>=a[i].v) {
        ++cnt,++j;
    }
    print(cnt),puts("");
}