tg 11 题解

T1

单调栈维护每个数可以做最大值的区间范围
记当前点的左端点为\(s\),右端点为\(t\),位置为\(pos\)
当前点的贡献:\((pos-s+1)*(t-pos+1)\)
然后就大力离散化维护前缀和即可
我不会用std::unique就手写了

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long 
const int o=2e5+22;
int a[o],n,q,b[o],c[o],cnt;
char ch[o];
struct node{
    int s,t;
    int id,val,exp;
}p[o];
bool cmp(node a,node b){
    return a.exp<b.exp;
}
void in(){
    scanf("%lld%lld",&n,&q);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
    }
}
void pre(){
    deque<node>q;
    for(int i=1;i<=n;i++){
        while(!q.empty()&&a[q.front().id]<a[i]){
            p[q.front().id].t=i-1;
            q.pop_front();
        }
        p[i].id=i,p[i].s=q.empty()?1:q.front().id+1;
        q.push_front(p[i]);
    }
    while(!q.empty()){
        p[q.front().id].t=n;
        q.pop_front();
    }
    for(int i=1;i<=n;i++){
        p[i].val=(p[i].id-p[i].s+1)*(p[i].t-p[i].id+1);
    //    printf("i=%d p[i].s=%d p[i].t=%d p[i].val=%d\n",i,p[i].s,p[i].t,p[i].val);
        p[i].exp=a[p[i].id];
    }
    sort(a+1,a+n+1),sort(p+1,p+n+1,cmp);
    for(int i=1;i<=n;i++){
        if(a[i]!=a[i-1]){
            cnt++;
        }
        c[cnt]=a[i];
    }
    cnt=0;
    for(int i=1;i<=n;i++){
        if(p[i].exp!=p[i-1].exp){
            cnt++;
            b[cnt]+=b[cnt-1];
        }
        b[cnt]+=p[i].val;
    //    printf("i=%d cnt=%d b[cnt]=%d\n",i,cnt,b[cnt]);
    }
}
void work(){
    for(int i=1,x;i<=q;i++){
        scanf("%s%lld",ch+1,&x);
        int now=lower_bound(c+1,c+cnt+1,x)-c;
        if(ch[1]=='>'){
            if(now==cnt+1){
                puts("0");
                continue;
            }
            if(c[now]>x){
                now--;
            }
            printf("%lld\n",b[cnt]-b[now]);
        }
        if(ch[1]=='='){
            if(x!=c[now]){
                puts("0");
                continue;
            }
            printf("%lld\n",b[now]-b[now-1]);
        }
        if(ch[1]=='<'){
            printf("%lld\n",b[now-1]);
        }
    }
}
signed main(){
    in();
    pre();
    work();
    return 0;
}


T2

一个离奇的东西就是这玩意用莫队
其实可以通过看部分分看出来正解是莫队
分析\(n,m\)的变化对于\(ans\)的贡献
语言难以描述我就直接代码块了

void up(int n,int m){
	ans=(2*ans%Mod-C(n,m)%Mod+Mod)%Mod;
}
void down(int n,int m){
	ans=(ans%Mod+C(n-1,m)%Mod)%Mod*qpow(2,Mod-2)%Mod;
}
void right(int n,int m){
	ans=(ans%Mod+C(n,m+1)%Mod)%Mod;
}
void left(int n,int m){
	ans=(ans%Mod-C(n,m)%Mod+Mod)%Mod;
}

于是剩下的就是莫队了
一些乱七八糟的分块和排序就不写了

T3

不会谁能不看题解切掉CF3000的题啊

T4

\(f[i][j]\)为当前放了\(i\)个数,\(j\)个值符合要求的方案数
转移从2个方向转移

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int o=222222,mod=998244353;
int f[2222][2222],k,ans,n;
void in(){
    scanf("%lld%lld",&n,&k);
}
void work(){
    f[1][0]=1;
    for(int i=2;i<=n;i++){
        for(int j=0;j<=min(i/2,k);j++){
            if(!j) {f[i][j]=(f[i-1][j]*(2*j+2)%mod)%mod;continue;}
            f[i][j]=(f[i-1][j-1]*(i-2*j)%mod+f[i-1][j]*(2*j+2)%mod)%mod;
        }
    }
}
void out(){
    ans=f[n][k];
    printf("%lld\n",ans);
}
signed main(){
    in();
    work();
    out();
}

posted @ 2022-07-25 11:33  2K22  阅读(41)  评论(0)    收藏  举报