冲刺清北营 4

今天成人礼。于是打算写点无营养鲜花。

口胡场都能被打自闭,真有你的。

一花 二乃 三玖 四叶 五月 六小.jpg

那你说的对。

猴戏世家

P4737。

场上脑抽,想到了后一半,没想到前一半。死于一直想从下到上扫描线无果,然后开始想怎么在线做。

从上到下扫描线,然后开个 set 维护栅栏。扫到一个点:

  1. 猴:找到右边第一个栅栏,就是它的。
  2. 栅栏:插入 set。

这样我们找到了每个栅栏包含哪些点。然后对于一个栅栏,它完全包含的在它后边加入的栅栏也是算作它的答案里的。这玩意显然成一个树形结构。于是并查集倒着扫一遍询问就行了。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <set>
using namespace std;
set<pair<int,int> >s;
int n,m,ans[300010],fa[300010],size[300010],f[300010];
struct node{
    int x,y,od;
    bool operator<(const node&s)const{
        return y==s.y?od>s.od:y>s.y;
    }
}p[600010];
int find(int x){
    return f[x]==x?f[x]:f[x]=find(f[x]);
}
void merge(int x,int y){
    x=find(x);y=find(y);
    if(x==y)return;
    f[y]=x;size[x]+=size[y];
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d%d",&p[i].x,&p[i].y);
    scanf("%d",&m);
    for(int i=1;i<=m;i++)scanf("%d%d",&p[n+i].x,&p[n+i].y),p[n+i].od=i,f[i]=i;
    sort(p+1,p+n+m+1);
    for(int i=1;i<=n+m;i++){
        if(p[i].od){
            s.insert(make_pair(p[i].x,p[i].od));
            set<pair<int,int> >::iterator it=s.find(make_pair(p[i].x,p[i].od));
            if(++it!=s.end())fa[p[i].od]=it->second;
            while(1){
                it=s.find(make_pair(p[i].x,p[i].od));
                if(it==s.begin())break;
                --it;
                if(it->second>p[i].od)s.erase(it);
                else break;
            }
        }
        else{
            set<pair<int,int> >::iterator it=s.lower_bound(make_pair(p[i].x,0));
            if(it!=s.end())size[it->second]++;
        }
    }
    for(int i=m;i>=1;i--){
        ans[i]=size[find(i)];
        if(fa[i])merge(fa[i],i);
    }
    for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
    return 0;
}

零糖麦片

CF468E。

啊这。

首先这玩意叫积和式不叫集合式。然后算这玩意没多项式复杂度解法。

于是考虑一个状压:先所有 \(w-1\)。然后设修改过的行的集合为 \(S\),每次枚举 \(S\) 的合法的子集代表选中了这些 \(w\),如果选了 \(t\) 个那么贡献乘个 \((n-t)!\)。正确性显然,复杂度 \(O(k^22^k)\) 的,显然过不去。

考虑优化,发现如果一行只有一个元素可能被选,那么不用把它压进状态里,于是只需要考虑修改元素个数 \(\ge 2\) 的行,复杂度变成 \(O(k^22^{\frac k2})\)

看起来极限情况还是过不去。那么加个玄学优化:扫完了所有状态的行显然可以去掉,那么我们先扫元素个数少的行。然后跑的飞快。

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <vector>
#include <unordered_map>
#define int long long
using namespace std;
const int mod=1000000007;
int n,k,ans,jc[100010],lsh1[60],lsh2[60],x[60],y[60],w[60],a[60][60],cnt1[60],cnt2[60];
unordered_map<int,int>dp[2][60];
signed main(){
    memset(a,-1,sizeof(a));
    scanf("%lld%lld",&n,&k);jc[0]=1;
    for(int i=1;i<=n;i++)jc[i]=1ll*jc[i-1]*i%mod;
    for(int i=1;i<=k;i++){
        scanf("%lld%lld%lld",&x[i],&y[i],&w[i]);w[i]=(w[i]+mod-1)%mod;
        lsh1[++lsh1[0]]=x[i];lsh2[++lsh2[0]]=y[i];
    }
    sort(lsh1+1,lsh1+lsh1[0]+1);sort(lsh2+1,lsh2+lsh2[0]+1);
    lsh1[0]=unique(lsh1+1,lsh1+lsh1[0]+1)-lsh1-1;
    lsh2[0]=unique(lsh2+1,lsh2+lsh2[0]+1)-lsh2-1;
    for(int i=1;i<=k;i++){
        x[i]=lower_bound(lsh1+1,lsh1+lsh1[0]+1,x[i])-lsh1;
        y[i]=lower_bound(lsh2+1,lsh2+lsh2[0]+1,y[i])-lsh2;
        a[x[i]][y[i]]=w[i];
        cnt1[x[i]]++;cnt2[y[i]]++;
    }
    dp[0][0][0]=1;int cur=0;
    while(1){
        int od=-1;
        for(int i=1;i<=lsh2[0];i++){
            if(cnt2[i]&&(od==-1||cnt2[od]>cnt2[i]))od=i;
        }
        if(od==-1)break;
        for(int i=1;i<=lsh1[0];i++){
            if(a[i][od]!=-1&&cnt1[i]){
                cnt1[i]=0;
                int s=(1ll<<lsh2[0])-1<<1,t=0;
                vector<int>ret;
                for(int j=1;j<=lsh2[0];j++){
                    if(a[i][j]!=-1){
                        ret.push_back(j);
                        cnt2[j]--;t|=1ll<<j;
                        if(!cnt2[j])s^=1ll<<j;
                    }
                }
                cur^=1;
                for(int j=0;j<=k;j++)dp[cur][j].clear();
                for(int z=0;z<=k;z++){
                    for(pair<int,int>p:dp[cur^1][z]){
                        dp[cur][z][p.first&s]=(dp[cur][z][p.first&s]+p.second)%mod;
                        for(int x:ret){
                            if(!((p.first>>x)&1)){
                                dp[cur][z+1][(p.first|(1ll<<x))&s]=(dp[cur][z+1][(p.first|(1ll<<x))&s]+1ll*p.second*a[i][x])%mod;
                            }
                        }
                    }
                }
            }
        }
    }
    for(int i=0;i<=k;i++)for(pair<int,int>p:dp[cur][i])ans=(ans+1ll*p.second*jc[n-i])%mod;
    printf("%lld\n",ans);
    return 0;
}

文体双花

线段树扫描线 + 单调栈。签到题,具体参考 pudding monsters。

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <bitset>
#include <queue>
#define int long long
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
const int mod=1000000007;
int n,p[100010],dp[100010];
struct node{
    int min,cnt;
    node operator+(const int &s)const{
        return{min+s,cnt};
    }
    node friend operator+(node s,node t){
        node ret={};
        ret.min=std::min(s.min,t.min);
        if(ret.min==s.min)ret.cnt+=s.cnt;
        if(ret.min==t.min)ret.cnt+=t.cnt;
        ret.cnt%=mod;
        return ret;
    }
};
struct Seg{
    int lz;
    node val;
}tree[400010];
void pushup(int rt){
    tree[rt].val=tree[lson].val+tree[rson].val;
}
void pushtag(int rt,int val){
    tree[rt].val=tree[rt].val+val;tree[rt].lz+=val;
}
void pushdown(int rt){
    if(tree[rt].lz){
        pushtag(lson,tree[rt].lz);
        pushtag(rson,tree[rt].lz);
        tree[rt].lz=0;
    }
}
void update(int rt,int L,int R,int l,int r,int val){
    if(l<=L&&R<=r){
        pushtag(rt,val);return;
    }
    pushdown(rt);
    int mid=(L+R)>>1;
    if(l<=mid)update(lson,L,mid,l,r,val);
    if(mid<r)update(rson,mid+1,R,l,r,val);
    pushup(rt);
}
void updatecnt(int rt,int L,int R,int pos,int val){
    if(L==R){
        tree[rt].val.cnt=val;return;
    }
    pushdown(rt);
    int mid=(L+R)>>1;
    if(pos<=mid)updatecnt(lson,L,mid,pos,val);
    else updatecnt(rson,mid+1,R,pos,val);
    pushup(rt);
}
node query(int rt,int L,int R,int l,int r){
    if(l<=L&&R<=r)return tree[rt].val;
    int mid=(L+R)>>1;
    node val={0x3f3f3f3f,0};
    if(l<=mid)val=val+query(lson,L,mid,l,r);
    if(mid<r)val=val+query(rson,mid+1,R,l,r);
    return val;
}
int stk1[100010],stk2[100010],top1,top2;
signed main(){
    scanf("%lld",&n);
    for(int i=1;i<=n;i++)scanf("%lld",&p[i]);
    dp[0]=1;
    for(int i=1;i<=n;i++){
        updatecnt(1,1,n,i,dp[i-1]);
        while(top1&&p[i]<=p[stk1[top1]]){
            update(1,1,n,stk1[top1-1]+1,stk1[top1],p[stk1[top1]]);
            top1--;
        }
        while(top2&&p[i]>=p[stk2[top2]]){
            update(1,1,n,stk2[top2-1]+1,stk2[top2],-p[stk2[top2]]);
            top2--;
        }
        update(1,1,n,stk1[top1]+1,i,-p[i]);
        update(1,1,n,stk2[top2]+1,i,p[i]);
        stk1[++top1]=stk2[++top2]=i;
        update(1,1,n,i,i,i);
        dp[i]=query(1,1,n,1,i).cnt;
    }
    printf("%lld\n",dp[n]);
    return 0;
}
posted @ 2023-04-22 20:04  gtm1514  阅读(25)  评论(2编辑  收藏  举报