8.9 NOIP模拟测试15 建设城市(city)+轰炸行动(bomb)+石头剪刀布(rps)

鉴于T3的惨烈程度,我决定先来颓篇题解。

T1 建设城市(city)

挡板法+容斥

m个建设队分成n组,每组必须有一个,先不考虑上限,共有 C(m-1,n-1)种方案。

有i个组是超过k个的,容斥掉 C(n,i)*C(m-i*k-1,n-1) 相当于把i×k个建设队拿出来,把剩下的m-i*k个建设队分成n组并且保证每个组都至少有一个且不考虑上界,再把这i个k放进n个分组里,就至少有i个组是大于k的。

#include<iostream>
#include<cstring>
#include<cstdio>
#define mod 998244353
#define ll long long
using namespace std;
ll n,m,k,fac[10001000],inv[10001000],facinv[10001000],ans;
ll C(ll x,ll y)
{
    if(y>x) return 0;
    return fac[x]*facinv[y]%mod*facinv[x-y]%mod;
}
int main()
{
    scanf("%lld%lld%lld",&n,&m,&k);
    if(n>m){
        puts("0");
        return 0;
    }
    fac[0]=1;facinv[0]=1;inv[1]=1;
    for(int i=1;i<=max(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]*inv[i]%mod;
    }
    for(int i=1;i<=n;i++){
        if(i&1) ans=(ans+C(n,i)*C(m-i*k-1,n-1))%mod;
        else ans=(ans-C(n,i)*C(m-i*k-1,n-1)+mod)%mod;
    }
    printf("%lld\n",(C(m-1,n-1)-ans+mod)%mod);
    return 0;
}
city

 

T2 轰炸行动(bomb)

考场好多看错题的,但是我没看错也没做出来(就是个废物)

移动是只要是有路径能到达就可以,那么我们tarjan缩点,缩完点后建新图,找最长链,每个点的深度应是父节点深度+点的size(几个点缩在一起),topu或dfs求最长链(但dfs好像容易T)。

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
struct node
{
    int to,nxt;
}h[4001000],hh[4001000];
int n,m,nxt[4001000],tot,tet,cnt,dfn[1001000],low[1001000],s[1001000];
int top,num,whos[1001000],sz[1001000],du[1001000],dep[1001000],ans,nx[4001000];
bool is[1001000];
int max(int x,int y)
{
    return x>y?x:y;
}
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--];
            is[tmp]=0;
            whos[tmp]=num;
            sz[num]++;
            if(x==tmp) break;
        }
    }
}
void topu()
{
    queue<int>q;
    for(int i=1;i<=num;i++)
        if(du[i]==0) q.push(i),dep[i]=sz[i],ans=max(ans,dep[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;
            du[y]--;
            dep[y]=max(dep[y],dep[x]+sz[y]);
            ans=max(ans,dep[y]);
            if(!du[y]) q.push(y);
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    int u,v;
    for(int i=1;i<=m;i++){
        scanf("%d%d",&u,&v);
        add(u,v);
    }
    for(int i=1;i<=n;i++)
        if(!dfn[i]) tarjan(i);
    for(int i=1;i<=n;i++){
        for(int j=nxt[i];j;j=h[j].nxt){
            int y=h[j].to;
            if(whos[i]!=whos[y]){
                ad(whos[i],whos[y]);
                du[whos[y]]++;
            }
        }
    }
    topu();
    printf("%d\n",ans);
}
bomb

 

T3 石头剪刀布(rps)

 

转载于:https://www.cnblogs.com/jrf123/p/11328044.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
NOI(全国青少年信息学奥林匹克竞赛)模拟赛的测试数据是指用于评测参赛选手的程序的输入和对应的输出。测试数据是非常重要的,因为它决定了参赛选手的程序能否正确地解决问题。 在NOI模拟赛中,测试数据具有以下特点: 1.充分覆盖:测试数据应涵盖各种可能的输入情况,包括边界条件和极端情况。通过提供不同的测试数据,可以考察选手对问题的全面理解和解决能力。 2.随机性和均衡性:为了公平起见,测试数据应该是随机生成的,而不是针对某个特定算法或解法设计的。同时,测试数据应该是均衡的,即各种情况的概率应该大致相等,以避免偏向某些解法。 3.合理性和可行性:测试数据应该是合理和可行的,即符合题目要求的输入数据,并且是选手能够通过编写程序来处理的。测试数据应该考虑到程序的限制和时间复杂度,以充分测试选手的编程能力。 NOI模拟赛的测试数据通常由经验丰富的考题组负责生成。他们会根据题目的要求和限制,设计出一组合理、充分、随机和均衡的测试数据,以确保参赛选手的程序在各种情况下都能正确运行,并且能通过性能测试。 总之,测试数据在NOI模拟赛中起到了至关重要的作用,它既考察了选手对问题的理解和解决能力,又提高了选手编程的技巧和效率。同时,合理和恰当的测试数据也是公平竞赛的保证,确保每个参赛选手有相同的机会和条件进行竞争。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值