【NOIP模拟8.4】

T1 打工

PS:本人比较懒就不发原题了(orz),网上查就有
想到了是DP但是转移有一点问题(雾…),然后只好特判+爆搜水过20分

题解:

30分做法
首先我们发现得到的序列有一个性质,即 a[i]<=max(a[j])+1 (j<i)
根据这个性质我们可以暴力地枚举每种方案,判断给出的序列属于哪个方案
50分做法
30分做法+特判两个特殊的点(递推)
70分做法
记忆化搜索(同100分做法)
100分做法
f[i][j] 表示i待选时,前i-1个数的最大值为j时的方案数
易得 f[i][j]=f[i1][j]×j+f[i1][j1]
枚举 i 的同时维护一个前缀最大值max,将与 a 的前i1位严格相同,第 i 位为1~ a[i]1 的答案累加到 f[i][max] 即可,答案就是 ni=1f[n][i]
考虑到空间可能爆,滚动数组优化即可

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;

const int N=10010,mod=1000007;
LL f[2][N];
int maxn,n,a[N];
LL ans;
int main()
{
//  freopen("maou.in","r",stdin);
//  freopen("maou.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    maxn=a[1];
    bool u=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=i;j++)
            f[u][j]=(f[!u][j]*j+f[!u][j-1])%mod;
        f[u][maxn]=(f[u][maxn]+a[i]-1)%mod;
//      for(int k=1;k<=i;k++) cout<<f[u][k]<<" ";
//      cout<<endl;
        maxn=max(maxn,a[i]);
        u=!u;       
    }
    for(int i=1;i<=n;i++)
        ans=(ans+f[!u][i])%mod;
    printf("%lld",ans+1);
    return 0;   
}

T2 破解

30分做法
暴力枚举选择哪些区间,哈希判重
100分做法
考虑一种特殊情况,如果所有的区间都不相互覆盖,那么设有 m 个区间,可以得到的串数目就是2m
对于每一个区间 [L,R] ,连一条 L R+1的边(手玩一下就知道为什么了)
那么这样一直加边,如果构成一个联通块(大小为 size ),那么通过这个连通块的任意 size1 条边代表的区间都能组成第 size 条边代表的区间,那么这个区间其实是没有用的,而且从这个连通块中任意选若干条边都不会构成重复的区间,所以这个连通块对答案的贡献就是 2size1 ,最后的答案就应该 2mcnt ,其中 cnt 为连通块个数
维护连通块的话并查集就好了,可以将询问的区间离散化一下,因为L,R都比较小不离散化也可以,注意一些细节就好

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;

const int mod=1000000007;
int fa[10000005];
int n,ans,m;

int find(int x)
{
    if(fa[x]!=x) fa[x]=find(fa[x]);
    return fa[x];   
}

int main()
{
//  freopen("steins.in","r",stdin);
//  freopen("steins.out","w",stdout);
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n+1;i++) fa[i]=i;//!!
        ans=1;
        for(int i=1,l,r;i<=m;i++)
        {
            scanf("%d%d",&l,&r);
            int r1=find(l),r2=find(r+1);
            if(r1!=r2) fa[r1]=r2,ans=(ans<<1)%mod;      
        }
        printf("%d\n",ans);
    }
    return 0;
}

T3 书稿

题解:
待更(本人现在还不会QAQ)……
各种二维差分的差分的前缀和的前缀和的前缀和乱搞

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值