2021.11.11考试总结[冲刺NOIP模拟28]

T1 嗑瓜子

DP状态记现有几个瓜子,几个瓜子壳,按题意转移即可。

\(code:\)

T1
#include<bits/stdc++.h>
using namespace std;

namespace IO{
	typedef long long LL; typedef long double LD;
	typedef unsigned long long ULL; typedef double DB;
	#define int long long
	#define freopen FL=freopen
	FILE *FL;
	const int Mxdt=100000;
	static char buf[Mxdt],Ch[50],*p1=buf,*p2=buf;
	inline char gc(){ return p1==p2&&(p2=(p1=buf)+fread(buf,1,Mxdt,stdin),p1==p2)?EOF:*p1++; }
	inline int read(){
		int t=0,f=0;char v=gc();
		while(v<'0')f|=(v=='-'),v=gc();
		while(v>='0')t=(t<<3)+(t<<1)+v-48,v=gc();
		return f?-t:t;
	}
	void write(int x,char sp){
		int len=0;
		if(x<0) x=-x,putchar('-');
		do{ Ch[len++]=x%10+'0'; x/=10; }while(x);
		for(int i=len-1;~i;i--) putchar(Ch[i]); putchar(sp);
	}
	void ckmin(int& x,int y){ x=x<y?x:y; }
	void ckmax(int& x,int y){ x=x>y?x:y; }
} using namespace IO;

const int NN=2010,mod=998244353;
int n,inv[NN<<2],f[NN][NN<<1];
int qpow(int a,int b,int res=1){
	for(;b;b>>=1,a=a*a%mod)
		if(b&1) res=res*a%mod;
	return res;
}

int dfs(int fi,int se){
	if(f[fi][se]) return f[fi][se];
	if(!fi) return 0;
	int tmp=fi*inv[fi+se]%mod;
	f[fi][se]=1;
	(f[fi][se]+=dfs(fi-1,se+2)*tmp)%=mod;
	if(se) (f[fi][se]+=dfs(fi,se-1)*(mod+1-tmp))%=mod;
	return f[fi][se];
}

signed main(){
	freopen("eat.in","r",stdin);
	freopen("eat.out","w",stdout);
	n=read();
	for(int i=1;i<=(n*3);i++) inv[i]=qpow(i,mod-2);
	write(dfs(n,0),'\n');
	return 0;
}

T2 第k大查询

考虑每个数的贡献,枚举每个数左边大于它数的个数,按点权顺序加点保证当前序列中所有数都大于它,然后双向链表维护即可。

\(code:\)

T2
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;

namespace IO{
    typedef long long LL; typedef long double LD;
    typedef unsigned long long ULL; typedef double DB;
    #define freopen FL=freopen
    FILE *FL;
    const int Mxdt=100000;
    static char buf[Mxdt],Ch[50],*p1=buf,*p2=buf;
    inline char gc(){ return p1==p2&&(p2=(p1=buf)+fread(buf,1,Mxdt,stdin),p1==p2)?EOF:*p1++; }
    inline int read(){
        int t=0,f=0;char v=gc();
        while(v<'0')f|=(v=='-'),v=gc();
        while(v>='0')t=(t<<3)+(t<<1)+v-48,v=gc();
        return f?-t:t;
    }
    void write(LL x,char sp){
        int len=0;
        if(x<0) x=-x,putchar('-');
        do{ Ch[len++]=x%10+'0'; x/=10; }while(x);
        for(int i=len-1;~i;i--) putchar(Ch[i]); putchar(sp);
    }
    void ckmin(int& x,int y){ x=x<y?x:y; }
    void ckmax(int& x,int y){ x=x>y?x:y; }
} using namespace IO;

const int NN=500001;
int n,k,pos[NN],tol[NN],tor[NN];
int pl,pr,lenl[50],lenr[50];
LL ans;
set<int>s;

void add(int p){
    s.insert(p);
    if(s.find(p)!=s.begin()){
        pl=*(--s.find(p));
        tor[pl]=p; tol[p]=pl;
    }
    if(s.find(p)!=--s.end()){
        pr=*(++s.find(p));
        tor[p]=pr; tol[pr]=p;
    }
}
void solve(int p){
    memset(lenl,0,sizeof(lenl));
    memset(lenr,0,sizeof(lenr));
    add(pos[p]); pl=pr=pos[p];
    for(int i(0);i<=k;i++){
        if(pl>=1){ lenl[i]=pl-tol[pl]; pl=tol[pl]; }
        if(pr<=n){ lenr[i]=tor[pr]-pr; pr=tor[pr]; }
        if(pl<1&&pr>n) break;
    }
    for(int i(0),j(k);i<=k;i++,j--) if(lenl[i]&&lenr[j])
        ans+=1ll*p*lenl[i]*lenr[j];
}

signed main(){
    freopen("kth.in","r",stdin);
    freopen("kth.out","w",stdout);
    n=read(); k=read()-1;
    for(int i(1);i<=n;i++)
        pos[read()]=i,tor[i]=n+1;
    for(int i(n);i;i--) solve(i);
    write(ans,'\n');
    return 0;
}

T3 树上路径

两条路径总可以被一条边分到两部分。记 \(down_v\)\(v\) 子树的直径, \(up_v\) 为过 \(v\) 父亲而不过 \(v\) 的最长链,就可以用这两个数组更新答案。更新时取后缀最大值。

考虑如何求。 \(down\) 直接树规,求 \(up_v\) 有两种情况,记 \(u\)\(v\) 父亲:

  • 组成 \(up_u\) 的两条链,一条是 \(u\) 上方的链,一条是 \(u\) 下方且不属于子树 \(v\) 的链

  • 组成 \(up_v\) 的两条链都是 \(u\) 下方且不属于子树 \(v\) 的链

因此维护 \(v\) 子树内最长链,次长链和次次长链,与 \(v\) 从父亲方向来的最长链,分类讨论转移。

参考博客:Blog

\(code:\)

T3
#include<bits/stdc++.h>
using namespace std;

namespace IO{
    typedef long long LL; typedef long double LD;
    typedef unsigned long long ULL; typedef double DB;
    #define freopen FL=freopen
    FILE *FL;
    const int Mxdt=100000;
    static char buf[Mxdt],Ch[50],*p1=buf,*p2=buf;
    inline char gc(){ return p1==p2&&(p2=(p1=buf)+fread(buf,1,Mxdt,stdin),p1==p2)?EOF:*p1++; }
    inline int read(){
        int t=0,f=0;char v=gc();
        while(v<'0')f|=(v=='-'),v=gc();
        while(v>='0')t=(t<<3)+(t<<1)+v-48,v=gc();
        return f?-t:t;
    }
    void write(LL x,char sp){
        int len=0;
        if(x<0) x=-x,putchar('-');
        do{ Ch[len++]=x%10+'0'; x/=10; }while(x);
        for(int i=len-1;~i;i--) putchar(Ch[i]); putchar(sp);
    }
    void ckmin(int& x,int y){ x=x<y?x:y; }
    void ckmax(int& x,int y){ x=x>y?x:y; }
} using namespace IO;

const int NN=500010;
int n,idx,head[NN];
int up[NN],down[NN],f[NN][4],g[NN][2];
int mx[NN];
LL ans;

struct edge{ int to,nex; }e[NN<<1];
void add(int a,int b){
    e[++idx]=(edge){b,head[a]}; head[a]=idx;
    e[++idx]=(edge){a,head[b]}; head[b]=idx;
}

void dfs1(int s,int fa){
    for(int v,i=head[s];i;i=e[i].nex) if((v=e[i].to)!=fa){
        dfs1(v,s);
        int tmp=f[v][0]+1;
        if(tmp>f[s][0]) swap(f[s][0],tmp);
        if(tmp>f[s][1]) swap(f[s][1],tmp);
        if(tmp>f[s][2]) swap(f[s][2],tmp);
        ckmax(down[s],down[v]);
    }
    ckmax(down[s],f[s][0]+f[s][1]);
}
void dfs2(int s,int fa){
    for(int v,i=head[s];i;i=e[i].nex) if((v=e[i].to)!=fa){
        int tmp=down[v];
        if(tmp>g[s][0]) swap(g[s][0],tmp);
        if(tmp>g[s][1]) swap(g[s][1],tmp);
    }
    for(int v,i=head[s];i;i=e[i].nex) if((v=e[i].to)!=fa){
        if(f[s][0]==f[v][0]+1){
            f[v][3]=max(f[s][1],f[s][3])+1;
            up[v]=max(f[s][2],f[s][3])+f[s][1];
        } else if(f[s][1]==f[v][0]+1){
            f[v][3]=max(f[s][0],f[s][3])+1;
            up[v]=max(f[s][2],f[s][3])+f[s][0];
        } else{
            f[v][3]=max(f[s][0],f[s][3])+1;
            up[v]=max(f[s][1],f[s][3])+f[s][0];
        }
        if(g[s][0]==down[v]) ckmax(up[v],g[s][1]);
        else ckmax(up[v],g[s][0]);
        dfs2(v,s);
    }
}

signed main(){
    freopen("tree.in","r",stdin);
    freopen("tree.out","w",stdout);
    n=read();
    for(int a,b,i=1;i<n;i++)
        a=read(),b=read(),add(a,b);
    dfs1(1,0); dfs2(1,0);
    for(int i=2;i<=n;i++){
        ckmax(mx[down[i]+1],up[i]+1);
        ckmax(mx[up[i]+1],down[i]+1);
    }
    for(int i=n;i;i--) ckmax(mx[i],mx[i+1]),ans+=mx[i];
    write(ans,'\n');
    return 0;
}

T4 糖

image

处理 \(3(2)\) 时可以视为每次遇到较优的位置就操作,并记购买价格为 \(sell\) ,这样迭代到最后可以保证操作位置是最优的。

\(code:\)

T4
#include<bits/stdc++.h>
using namespace std;

namespace IO{
    typedef long long LL; typedef long double LD;
    typedef unsigned long long ULL; typedef double DB;
    #define int long long
    typedef pair<int,int> PII;
    #define mpr make_pair
    #define fi first
    #define se second
    #define freopen FL=freopen
    FILE *FL;
    const int Mxdt=100000;
    static char buf[Mxdt],Ch[50],*p1=buf,*p2=buf;
    inline char gc(){ return p1==p2&&(p2=(p1=buf)+fread(buf,1,Mxdt,stdin),p1==p2)?EOF:*p1++; }
    inline int read(){
        int t=0,f=0;char v=gc();
        while(v<'0')f|=(v=='-'),v=gc();
        while(v>='0')t=(t<<3)+(t<<1)+v-48,v=gc();
        return f?-t:t;
    }
    void write(int x,char sp){
        int len=0;
        if(x<0) x=-x,putchar('-');
        do{ Ch[len++]=x%10+'0'; x/=10; }while(x);
        for(int i=len-1;~i;i--) putchar(Ch[i]); putchar(sp);
    }
    void ckmin(int& x,int y){ x=x<y?x:y; }
    void ckmax(int& x,int y){ x=x>y?x:y; }
} using namespace IO;

const int NN=200010;
int n,c,ans,a[NN],b[NN],s[NN];
int in;
deque<PII>q;

signed main(){
    freopen("candy.in","r",stdin);
    freopen("candy.out","w",stdout);
    n=read(); c=read();
    for(int i=1;i<=n;i++) a[i]=read();
    for(int i=0;i<n;i++) b[i]=read(),s[i]=read();
    in=c-(a[1]-a[0]); ans=(a[1]-a[0])*b[0]; q.push_back(mpr(in,b[0]));
    for(int i=1;i<n;i++){
        while(!q.empty()&&q.back().se>b[i]) in-=q.back().fi,q.pop_back();
        if(in<c) q.push_back(mpr(c-in,b[i])); in=c;
        while(!q.empty()&&q.front().se<=s[i])
            in-=q.front().fi,ans-=q.front().fi*(s[i]-q.front().se),q.pop_front();
        if(in<c) q.push_front(mpr(c-in,s[i])); in=c;
        while(a[i]<a[i+1]){
            PII tmp=q.front(); q.pop_front();
            if(a[i]+tmp.fi<=a[i+1]){
                in-=tmp.fi;
                ans+=tmp.fi*tmp.se;
                a[i]+=tmp.fi;
            } else{
                in-=a[i+1]-a[i];
                ans+=(a[i+1]-a[i])*tmp.se;
                tmp.fi-=a[i+1]-a[i];
                a[i]=a[i+1];
                q.push_front(tmp);
            }
        }
    }
    write(ans,'\n');
    return 0;
}
posted @ 2021-11-11 20:41  keen_z  阅读(57)  评论(0)    收藏  举报