补题 HNCPC2021 EFG

只补了E,F,G题,就当作补了道EGF的题好了!

E.Not the Only Tree

建个二叉树,然后树上DP

就很一眼吧

ll POW(ll a,ll k=P-2,ll res=1){while(k){if(k&1)res=res*a%P;a=a*a%P;k>>=1;}return res;}
const int N=1e3+10;
ll fac[N],finv[N];
void init()
{
	fac[0]=1;
	for(int i=1;i<N;++i)fac[i]=fac[i-1]*i%P;
	finv[N-1]=POW(fac[N-1]);
	for(int i=N-2;i;--i)finv[i]=finv[i+1]*(i+1)%P;
	finv[0]=1;
}
int a[N];
ll C(int a,int b){return fac[a]*finv[a-b]%P*finv[b]%P;}
int root;
struct Node
{
	int l,r,val,siz,lsz;
}tr[N];
int pos;
void add(int u,int val)
{
    ++tr[u].siz;
	if(!tr[u].val){tr[u].val=val;return ;}
	
	if(tr[u].val<val)
	{
		if(!tr[u].r)tr[u].r=++pos;
		add(tr[u].r,val);
	}
	else if(tr[u].val>val)
	{
		if(!tr[u].l)tr[u].l=++pos;
		++tr[u].lsz;
		add(tr[u].l,val);
	}
}
/*void print_tree(int u)
{
	
	if(tr[u].l)dfs2(tr[u].l);
	printf("%d ",tr[u].val);
	if(tr[u].r)dfs2(tr[u].r);
}*/
ll dp[N];
void dfs(int u)
{
	dp[u]=C(tr[u].siz-1,tr[u].lsz);
	//{cout<<"check :"<<dp[u]<<" "<<tr[u].siz<<" "<<tr[u].lsz<<" "<<u<<endl;}
	if(tr[u].l)
	{
		dfs(tr[u].l);
		dp[u]=dp[u]*dp[tr[u].l]%P;
	}
	if(tr[u].r)
	{
	dfs(tr[u].r);
	dp[u]=dp[u]*dp[tr[u].r]%P;
	}
}
void debug(int u)
{
	cout<<"now :"<<tr[u].lsz<<endl;
}
int main()
{
	init();
	int  n;
	while(scanf("%d",&n)!=EOF)
	{
		for(int i=1;i<=n;++i)scanf("%d",&a[i]);
		memset(tr,0,sizeof(tr));
		pos=1,root=1;
		for(int i=1;i<=n;++i)add(root,a[i]);
		//print_tree(1);
		//debug();
		dfs(root);
		printf("%lld\n",dp[1]);
	}
}

F.最大的数

F题vp的时候想了个两个set+一个优先队列的做法,但因为时间不够就没写,最终选择了用题解的做法

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
bool st[N];
using pii=pair<int,int>;
void debug(string s){cout<<"now :"<<s<<endl;}
void debug(vector<vector<int>> mp)
{
    for(int i=0;i<=9;++i)
    {
        if(mp[i].size())cout<<"now is :"<<i<<'\n';
        for(auto v:mp[i])cout<<v<<" ";
        if(mp[i].size())cout<<'\n';
    }
}
void solve(string rs,int d)
{
    int n=rs.size();++d;
    vector<int> a(n);
    for(int i=0;i<n;++i)st[i]=0;
    for(int i=0;i<n;++i)a[i]=rs[i]-'0';
    vector<vector<int>> mp(10),stk(10);
    
    for(int i=0;i<=min(d,n-1);++i)stk[a[i]].push_back(i);
    
    for(int i=0;i<n;++i)
    {
        if(i+d<n&&i)stk[a[i+d]].push_back(i+d);
        if(st[i])continue;
        for(int j=9;j>a[i];--j)
        {
            if(stk[j].empty()||stk[j].back()<=i)continue;
            mp[j].push_back(i);
            st[stk[j].back()]=1;
            stk[j].pop_back();
            break;
        }
    }
    //debug(stk);
    vector<priority_queue<pii,vector<pii>,greater<pii>>> heap(10);
    for(int i=n-1;~i;--i)
    {
        if(st[i])
        {
            while(mp[a[i]].size()&&mp[a[i]].back()+d>=i)
            {heap[a[i]].push({a[mp[a[i]].back()],mp[a[i]].back()});mp[a[i]].pop_back();}
            auto v=heap[a[i]].top();
            heap[a[i]].pop();
            swap(rs[v.second],rs[i]);
        }
    }
    
    cout<<rs<<'\n';
    
}
int main()
{
    string s;int d;
    while(cin>>s>>d)solve(s,d);
}





G.洞穴探宝

做个G吧,然后就G了

这种题写少了,建图建假导致debug一晚上,什么事情都没做

建了个很蠢的图是我没想到的

#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
const int N=1e2+10;
char g[N][N];
using pii=pair<int,int>;
int pos;
vector<int> e[25];
pii id[25];
int mp[N][N];
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
bool st[N][N],vis[25],treasure[25],trap[25];
int n,m;
void get_graph(pii idn,int t)
{
    st[idn.x][idn.y]=1;
    for(int i=0;i<4;++i)
    {
        int x=idn.x+dx[i],y=idn.y+dy[i];
        if(x<1||x>n||y<1||y>m||(g[x][y]=='#')||st[x][y])continue;
        if(mp[x][y]!=-1)
        {
        e[t].push_back(mp[x][y]);
        continue;
        }
        get_graph({x,y},t);
        
    }
}
void init1()
{
    pos=0;
    memset(mp,-1,sizeof(mp));
    memset(treasure,0,sizeof(treasure));
    memset(trap,0,sizeof(trap));
    for(int i=0;i<25;++i)e[i].clear();
}
bool dp[1<<22][23];
void init2()
{
    for(int i=0;i<1<<pos+1;++i)for(int j=0;j<=pos;++j)dp[i][j]=0;
}
int test;

int dfs(int state,int p)
{
    if(dp[state][p])return 0;
    dp[state][p]=1;
    int rs=0;
    if(p==0)
    {
        int nw=state;
        // cout<<"now :"<<(++test)<<endl;
        // for(int i=0;i<=pos;++i)cout<<((state>>i)&1);cout<<'\n';
        for(int i=1;i<=pos;++i)
        {
        if((state>>i&1)&&treasure[i])++rs;
        if(state>>i&1)
        for(int j=0;j<4;++j)
        {
            int x=dx[j]+id[i].x,y=dy[j]+id[i].y;
            if(x<1||x>n||y>m||y<1||g[x][y]!='@')continue;
            if(!(nw&(1<<mp[x][y])))
            {++rs;nw|=1<<mp[x][y];}
           // cout<<x<<" "<<y<<endl;
           
        }
       // if(rs==3){for(int i=0;i<=pos;++i)cout<<((state>>i)&1);cout<<'\n';}
        }
    }
    for(auto v:e[p])
    {
        if((state&1<<v)&&trap[v])continue;
        rs=max(dfs(state|(1<<v),v),rs);
    }
    return rs;
}

void debug()
{
    for(int i=0;i<=pos;++i)
    {
        //if(e[i].size());
        cout<<"now is :"<<i<<endl;
        for(auto v:e[i])cout<<v<<" ";
        if(e[i].size())
        cout<<'\n';
    }
}
void init_graph()
{
    pii sta;
    for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)
    if((g[i][j]=='.')&&(i==1||i==n||j==1||j==m)){sta={i,j};break;}    
    id[0]=sta;mp[sta.x][sta.y]=0;
    //cout<<"now sta: "<<sta.x<<" "<<sta.y<<endl;
    for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)
    if(g[i][j]!='.'&&g[i][j]!='#')
    {
        id[++pos]={i,j};
        treasure[pos]=(g[i][j]=='@');
        trap[pos]=(g[i][j]=='X');
        mp[i][j]=pos;
    }
    for(int i=0;i<=pos;++i)
    {
        memset(st,0,sizeof(st));//memset(vis,0,sizeof(vis));
        get_graph(id[i],i);
        //if(i)e[i].push_back(0);
    }    
}
void solve()
{
    for(int i=1;i<=n;++i)scanf("%s",g[i]+1);
    init1();
    init_graph();
    init2();
    // debug();
    printf("%d\n",dfs(1,0));
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)solve();
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值