A-咪咪游戏

Solution

需要满足以下条件:

  • 字符串长度为偶数。
  • 奇数位是 ,偶数位是

从前到后扫描一遍即可。

时间复杂度

Code

#include <iostream>
#include <cstdio>
#include <cstring>
const int maxn=1e5+10;
using namespace std;
int n,q;
char ch[maxn];
int main(){
    ios::sync_with_stdio(false);
    cin>>q;
    int x;
    while(q--){
        cin>>(ch+1);
        n=strlen(ch+1);
        if(n%2==1){
            cout<<"No"<<endl;
            continue;
        }
        x=1;
        for(int i=1;i<=n;i++)
            if((i%2==1&&ch[i]!='m')||(i%2==0&&ch[i]!='q')){
                x=0;
                break;
            }
        if(x)
            cout<<"Yes"<<endl;
        else
            cout<<"No"<<endl;
    }
    return 0;
}

B-三角形

Solution

依次处理每个序列。若当前处理到第 个序列,在所有可能的和中只有前 小的可能会对最终答案产生贡献。那么就可以及时剔除其他情况。此过程可以使用大根堆来维护,每次将当前序列和合并成一个大小为 的数组即可。

关于合并两个数组得到新的和,使用的是经典的双指针法。

时间复杂度:

Code

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=1e6+10;
int ans,n,m,k,tot,a[maxn],b[maxn],c[maxn];
struct node{
    int x,y,z;
}heap[maxn<<1];
void up(int u){
    while(u>1){
        if(a[heap[u].x]+b[heap[u].y]<a[heap[u>>1].x]+b[heap[u>>1].y])
            swap(heap[u],heap[u>>1]);
        else
            break;
        u>>=1;
    }
}
void down(int u){
    int v=u<<1;
    while(v<=tot){
        if(v<tot&&a[heap[v+1].x]+b[heap[v+1].y]<a[heap[v].x]+b[heap[v].y])
            v++;
        if(a[heap[v].x]+b[heap[v].y]<a[heap[u].x]+b[heap[u].y])
            swap(heap[u],heap[v]);
        else
            break;
        u=v;
        v=u<<1;
    }
}
void insert(int i,int j,int q){
    heap[++tot].x=i;
    heap[tot].y=j;
    heap[tot].z=q;
    up(tot);
}
void extract(){
    heap[1]=heap[tot--];
    down(1);
}
int main(){
    ios::sync_with_stdio(false);
    cin>>n>>k;
    m=1;
    int len,cnt;
    for(int i=1;i<=n;i++){
        cin>>len;
        cnt=0;
        for(int j=1;j<=len;j++)
            cin>>b[j];
        sort(b+1,b+len+1);
        if(i==1)
            for(int j=1;j<=len;j++)
                a[j]=b[j];
        else{
            for(int j=1;j<=m;j++)
                for(int h=1;h<=len;h++)
                    c[++cnt]=a[j]+b[h];
            for(int j=1;j<=cnt;j++)
                a[j]=c[j];
            sort(a+1,a+cnt+1);
        }
        m*=len;
        if(m>=k){
            m=k,len=i;
            break;
        }
    }
    int u,v;
    for(int i=len+1;i<=n;i++){
        cin>>cnt;
        tot=0;
        for(int j=1;j<=cnt;j++)
            cin>>b[j];
        sort(b+1,b+cnt+1);
        insert(1,1,0);
        for(int j=1;j<=k;j++){
            u=heap[1].x;
            v=heap[1].y;
            c[j]=a[u]+b[v];
            if(v+1<=cnt)
                insert(u,v+1,1);
            if(!heap[1].z)
                insert(u+1,v,0);
            extract();
        }
        for(int j=1;j<=k;j++)
            a[j]=c[j];
    }
    for(int i=1;i<=k;i++)
        ans+=a[i];
    cout<<ans;
    return 0;
}

C-区间加

Solution

序列问题还是先想差分。设 为第 位还差多少到 的差分数组。之后依次考虑

  • ,则表明此处比上一处所需要的少 。那么可以在 处放置一个区间右端点。
  • ,则表明此处比上一处所需要的多 。那么可以在 处放置一个区间左端点。
  • ,则表明此处和上一处所需要的相等 。那么可以在 处放置一个区间左端点,在 处放置一个区间右端点,也可以都不放。
  • ,显然不可能成功。

所以只需要维护一个变量记录当前未匹配的左端点个数,再根据乘法原理更新答案即可。

时间复杂度:

Code

#include <iostream>
#include <cstdio>
#include <algorithm>
#define ll long long
using namespace std;
const int mod=998244355;
const int maxn=2e3+10;
int n,m,sum,a[maxn],b[maxn];
ll ans=1;
int main(){
    ios::sync_with_stdio(false);
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        a[i]=m-a[i];
    }
    for(int i=1;i<=n+1;i++)
        b[i]=a[i]-a[i-1];
    for(int i=1;i<=n+1;i++){
        if(b[i]>1||b[i]<-1){
            ans=0;
            break;
        }
        else if(b[i]==1)
            sum++;
        else if(!b[i])
            ans=(ans*(sum+1))%mod;
        else
            ans=(ans*sum)%mod,sum--;
    }
    cout<<ans;
    return 0;
}

D-多元组

Solution

显然是一道 题。设 表示前 个数组成 元组的方案数,那么有

然后发现这个前缀可以用树状数组维护:设 为小于 的数所能组成的 元组的数量。将数据离散化即可。

时间复杂度:

Code

#include <iostream>
#include <cstdio>
#include <algorithm>
#define ll long long
using namespace std;
const ll maxn=1e5+10;
const ll mod=1e9+7;
ll n,m,len,a[maxn],b[maxn],c[maxn],ans[maxn][52],t[maxn][52];
ll gtid(ll x){
    ll l=1,r=len,mid;
    while(l<r){
        mid=(l+r)>>1;
        if(c[mid]<x)
            l=mid+1;
        else
            r=mid;
    }
    return l;
}
ll lowbit(ll x){
    return x&(-x);
}
ll ask(ll x,ll y){
    ll sum=0;
    for(;x>0;x-=lowbit(x))
        sum=(sum+t[x][y])%mod;
    return sum;
}
void add(ll x,ll y,ll z){
    for(;x<=len;x+=lowbit(x))
        t[x][y]=(t[x][y]+z)%mod;
}
int main(){
    ios::sync_with_stdio(false);
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        b[i]=a[i];
    }
    sort(b+1,b+n+1);
    for(int i=1;i<=n;i++)
        if(b[i]!=b[i-1]||i==1)
            c[++len]=b[i];
    for(int i=1;i<=n;i++)
        ans[i][1]=1;
    ll x;
    for(int i=1;i<=n;i++){
        x=gtid(a[i]);
        add(x,1,1);
        for(int j=2;j<=m;j++){
            ans[i][j]=(ans[i][j]+ask(x-1,j-1))%mod;
            add(x,j,ans[i][j]);
        }
    }
    ll sum=0;
    for(int i=1;i<=n;i++)
        sum=(sum+ans[i][m])%mod;
    cout<<sum;
    return 0;
}