8.18 NOIP模拟测试25(B) 字符串+乌鸦喝水+所驼门王的宝藏

T1 字符串

卡特兰数

设1为向(1,1)走,0为向(1,-1)走,限制就是不能超过$y=0$这条线,题意转化为从(0,0)出发,走到(n+m,n-m)且不越过$y=0$,然后就裸的卡特兰数,$ans=C(n+m,n)-C(n+m,m-1)$

#include<iostream>
#include<cstdio>
#include<cstring>
#define mod 20100403
#define ll long long
using namespace std;
ll n,m,inv[2001000],fac[2001000],facinv[2001000];
ll read()
{
    ll aa=0,bb=1;char cc=getchar();
    while(cc>'9'||cc<'0'){if(cc=='-') bb=-1;cc=getchar();}
    while(cc<='9'&&cc>='0'){aa=(aa<<3)+(aa<<1)+(cc^'0');cc=getchar();}
    return aa*bb;
}
ll C(ll x,ll y)
{
    return fac[x]*facinv[x-y]%mod*facinv[y]%mod;
}
int main()
{
    n=read();m=read();
    fac[0]=1;facinv[0]=1;inv[1]=1;
    for(ll i=1;i<=n+m;i++){
        if(i!=1) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
        fac[i]=fac[i-1]*i%mod;
        facinv[i]=facinv[i-1]%mod*inv[i]%mod;
    }
    printf("%lld\n",(C(n+m,n)-C(n+m,m-1)+mod)%mod);
    return 0;
}
字符串

T2 乌鸦喝水

两条性质:

1.若水少的喝了$x$次,那么比他水多的至少喝了$x$次。所以按能喝的次数升序排列。

2.排序后的序列里,当前水缸还能喝的次数${\ge}k$,那么之后的水缸在这一轮也不会被喝完。

于是我们在排完序的序列里,每次找到最少的,看他能喝几轮,直接跳,所以用树状数组维护当前点的实际坐标的右边还可以喝$k$次,若$num>k+ans$那就飞一轮,同时更新答案,若$num<k+ans$,就在原序列上二分看他最多跳到哪(记得更新答案),同时把排序后的序列的下标向右推一位,因为这一位已经失效了。

树状数组的具体实现就是以原坐标为下标,插入每个点是否存在,存在为1,不存在为0,维护前缀和,查询的时候直接减就可以得到右边有多少个点。

#include<iostream>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
struct node
{
    int id,cnt;
}h[100100];
ll n,m,x,w[100100],a[100100],c[100100],ans,cir;
ll read()
{
    ll aa=0,bb=1;char cc=getchar();
    while(cc>'9'||cc<'0'){if(cc=='-') bb=-1;cc=getchar();}
    while(cc<='9'&&cc>='0'){aa=(aa<<3)+(aa<<1)+(cc^'0');cc=getchar();}
    return aa*bb;
}
bool cmp(node a,node b)
{
    return a.cnt==b.cnt?a.id<b.id:a.cnt<b.cnt;
}
int lowbit(int x)
{
    return x&(-x);
}
void insert(int x,int w)
{
    while(x<=n){
        c[x]+=w;
        x+=lowbit(x);
    }
}
int query(int x)
{
    int as=0;
    while(x){
        as+=c[x];
        x-=lowbit(x);
    }
    return as;
}
int main()
{
    n=read();m=read();x=read();
    for(int i=1;i<=n;i++) w[i]=read();
    for(int i=1,u;i<=n;i++){
        u=read();
        h[i].id=i;
        h[i].cnt=(x-w[i])/u+1;
        insert(i,1);
    }
    sort(h+1,h+n+1,cmp);
    int pos=1,las=1;//pos排序后的序列 las原序列
    for(int pos=1;pos<=n;pos++){
        while(cir<m&&query(n)-query(las-1)+ans<h[pos].cnt){
            cir++;
            ans+=query(n)-query(las-1);
            las=1;
        }
        if(cir>=m) break;
        int l=las,r=n,as=las-1;
        while(l<=r){
            int mid=(l+r)>>1;
            if(query(mid)-query(las-1)+ans<=h[pos].cnt){
                as=mid;
                l=mid+1;
            }
            else r=mid-1;
        }
        ans+=query(as)-query(las-1);
        las=(as==n)?1:as+1;
        if(as==n) cir++;
        insert(h[pos].id,-1);
    }
    printf("%lld\n",ans);
    return 0;
}
乌鸦喝水

T3 所驼门王的宝藏

考场看错题,周围8个点理解成向左右上下个拓展8个点,嘤嘤嘤

把每个传送门能去的有宝藏的地方建单向边,tarjan缩点,重新建边,topu找最长链。(因为是单向边,dfs是($n^2$)的,时间受不住,topu只需要($n^2$))

最恶心的是建边,用$vector$ 存每一行 每一列都有哪些宝藏(用于$opt==1||opt==2$),用$map$映射二元组记录每个点的位置(用于$opt==3$),然后直接建就行

#include<iostream>
#include<cstdio>
#include<vector>
#include<map>
#include<queue>
using namespace std;
struct node
{
    int to,nxt;
}h[10000010],hh[1000100];
struct nnde
{
    int x,y,opt;
}t[100100];
int ans;
int n,r,c,tot,nxt[10000010],opt[100100],tx[9]={0,0,-1,-1,-1,1,1,1},ty[9]={-1,1,-1,0,1,-1,0,1};
int nx[100100],tet,d[100100],val[100100];
int dfn[100100],low[100100],s[100100],top,whos[100100],cnt,num,shu[100100];
bool is[100100],vis[100100],v[500100];
vector<int>hang[1001000],lie[1001000],ve;
map< pair<int,int> ,int>mp;
int read()
{
    int aa=0,bb=1;char cc=getchar();
    while(cc>'9'||cc<'0'){if(cc=='-') bb=-1;cc=getchar();}
    while(cc<='9'&&cc>='0'){aa=(aa<<3)+(aa<<1)+(cc^'0');cc=getchar();}
    return aa*bb;
}
void add(int x,int y)
{
    h[++tot].to=y;
    h[tot].nxt=nxt[x];
    nxt[x]=tot;
}
void ad(int x,int y)
{
    hh[++tet].to=y;
    hh[tet].nxt=nx[x];
    nx[x]=tet;
}
void tarjan(int x)
{
    dfn[x]=low[x]=++cnt;
    s[++top]=x;is[x]=1;
    for(int i=nxt[x];i;i=h[i].nxt){
        int y=h[i].to;
        if(!dfn[y]){
            tarjan(y);
            low[x]=min(low[x],low[y]);
        }
        else if(is[y]) low[x]=min(low[x],dfn[y]);
    }
    if(dfn[x]==low[x]){
        num++;
        while(1){
            int tmp=s[top--];
            whos[tmp]=num;
            shu[num]++;
            is[tmp]=0;
            if(tmp==x) break;
        }
    }
}
void topu()
{
    queue<int>q;
    for(int i=1;i<=num;i++){
        if(!d[i]) q.push(i),val[i]=shu[i],ans=max(ans,val[i]);
    }
    while(q.size()){
        int x=q.front();q.pop();
        for(int i=nx[x];i;i=hh[i].nxt){
            int y=hh[i].to;
            d[y]--;
            val[y]=max(val[y],val[x]+shu[y]);
            ans=max(ans,val[y]);
            if(!d[y]) q.push(y);
        }
    }
}
int main()
{
    n=read();r=read();c=read();
    int x,y,opt;
    for(int i=1;i<=n;i++){
        t[i].x=read();t[i].y=read();t[i].opt=read();
        hang[t[i].x].push_back(i);
        lie[t[i].y].push_back(i);
        mp[make_pair(t[i].x,t[i].y)]=i;
    }
    for(int i=1;i<=n;i++){
        int x=t[i].x,y=t[i].y,opt=t[i].opt;
        if(opt==1){
            for(int j=0;j<hang[x].size();j++){
                if(i==hang[x][j]) continue;
                add(i,hang[x][j]);
            }
        }
        else if(opt==2){
            for(int j=0;j<lie[y].size();j++){
                if(i==lie[y][j]) continue;
                add(i,lie[y][j]);
            }
        }
        else if(opt==3){
            for(int j=0;j<8;j++){
                if(mp[make_pair(x+tx[j],y+ty[j])]){
                    add(i,mp[make_pair(x+tx[j],y+ty[j])]);
                }
            }
        }
    }
    for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
    for(int i=1;i<=n;i++){
        ve.clear();
        for(int j=nxt[i];j;j=h[j].nxt){
            int y=h[j].to;
            if(whos[y]!=whos[i]&&!vis[whos[y]]){
                ad(whos[i],whos[y]);
                d[whos[y]]++;
                ve.push_back(whos[y]);
                vis[whos[y]]=1;
            }
        }
        for(int j=0;j<ve.size();j++) vis[ve[j]]=0;
    }
    topu();
    printf("%d\n",ans);
    return 0;
}
所驼门王的宝藏

猜你喜欢

转载自www.cnblogs.com/jrf123/p/11373828.html
今日推荐