9.11NOIP模拟赛

Passward(passward.cpp)
你来到了一个庙前,庙牌上有一个仅包含小写字母的字符串 s。
传说打开庙门的密码是这个字符串的一个子串 t,并且 t 既是 s 的前缀又是 s 的后缀并且还在 s 的中间位置出现过一次。
如果存在这样的串,请你输出这个串,如有多个满足条件的串,输出最长的那一个。
如果不存在这样的串,输出”Just a legend”(去掉引号)。
输入格式:
仅一行,字符串 s。
输出格式:
如题所述
样例输入
fixprefixsuffix
样例输出:
fix
数据范围:
对于 60%的数据, s 的长度<=100
对于 100%的数据, s 的长度<=100000

题解:用kmp的思想,求出nxt[ ]后疯狂地跳就行,本人的代码好像不能处理多个循环节的情况(比如6个),所以WA了一个点。根据将标准in和out进行kmp(我真机智。。。),发现这是一组有三个循环节的数据,所以特判一下过的(if (m-nxt[m]==nxt[m]-nxt[nxt[m]])),正式考试不建议这么搞。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=1e5+4;
char W[MAXN];
int f[MAXN],m,ans=0;
int vis[MAXN];
inline void getfail(char *W) {
    f[0]=f[1]=0;
    for (int i=1;i<m;++i) {
        int j=f[i];
        while (j&&W[i]!=W[j]) j=f[j];
        f[i+1]=W[i]==W[j]?j+1:0;
    }
}
int main() {
    freopen("passward.in","r",stdin);
    freopen("passward.out","w",stdout);
    scanf("%s",W),m=strlen(W);
    getfail(W);
    memset(vis,0,sizeof(vis));
    for (int i=1;i<=m;++i) ++vis[f[i]];
    int t=f[m];
    if (m-f[m]==f[m]-f[f[m]]) t=f[f[m]];//abdbaa...abdbaa...abdbaa
    else if (f[m]==m-1) t=m-2;//"aaa...a"
    else while (vis[t]<=1) t=f[t];
    if (t==0) {puts("Just a legend");return 0;}
    for (int i=0;i<t;++i) printf("%c",W[i]);
    return 0;
}

就(so.cpp)
【背景描述】
一排 N 个数, 第 i 个数是 Ai , 你要找出 K 个不相邻的数, 使得他们的和最大。
请求出这个最大和。
【输入格式】
第一行两个整数 N 和 K。
接下来一行 N 个整数, 第 i 个整数表示 Ai 。
【输出格式】
一行一个整数表示最大和, 请注意答案可能会超过 int 范围
【样例输入】
3 2
4 5 3
【样例输出】
7
【数据范围】
对于 20% 的数据, N, K ≤ 20 。
对于 40% 的数据, N, K ≤ 1000 。
对于 60% 的数据, N, K ≤ 10000 。
对于 100% 的数据, N, K ≤ 100000 , 1 ≤ Ai ≤ 1000000000。

题解:用一个set维护所有位置,每次取出最大的,然后把这个位置和两边的位置合并,选择合并之后的位置就相当于取消选择原来的位置,并选择两边的位置。把原来的和两边的在set里删掉,再把合并之后的加入set里。可以用链表来维护两边的位置,重复K次即可。这里用到一个可以支持撤销操作的写法:a[top.id]=a[pre[top.id]]+a[nxt[top.id]]-a[top.id]; 自己想想吧,这个真的是只可意会不可言传,这里简单地强行扯几句(set是自动排序的,什么时候加到,会不会加到跟具体数据有关,某一时刻的最大值可能就是之前某一位取过的数的前驱后继之和,这种写法只是支持这样一种操作)。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<set>
using namespace std;
typedef long long ll;
const int MAXN=1e5+4;
int n,k,nxt[MAXN],pre[MAXN];
ll ans=0,a[MAXN];
struct node {
    ll w;int id;
    bool operator <(const node &a) const{
        return w==a.w?id<a.id:w>a.w;
    }
};
set<node> s;
inline int read() {
    int x=0;char c=getchar();
    while (c<'0'||c>'9') c=getchar();
    while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x;
}
int main() {
//  freopen("so1.in","r",stdin);
    freopen("so.in","r",stdin);
    freopen("so.out","w",stdout);
    s.clear();
    n=read(),k=read();
    for (register int i=1;i<=n;++i) nxt[i]=i+1,pre[i]=i-1,a[i]=read(),s.insert((node){a[i],i});
    nxt[n]=0,a[0]=1ll*(-1e18);
    for (register int r=1;r<=k;++r) {
        node top=*s.begin();
        s.erase((node){top.w,top.id});
        ans+=a[top.id];
        a[top.id]=a[pre[top.id]]+a[nxt[top.id]]-a[top.id];
        if (pre[top.id]) s.erase((node){a[pre[top.id]],pre[top.id]});
        if (nxt[top.id]) s.erase((node){a[nxt[top.id]],nxt[top.id]});
        s.insert((node){a[top.id],top.id});
        if (pre[pre[top.id]]) nxt[pre[pre[top.id]]]=top.id;
        if (nxt[nxt[top.id]]) pre[nxt[nxt[top.id]]]=top.id;
        pre[top.id]=pre[pre[top.id]];
        nxt[top.id]=nxt[nxt[top.id]];
    }
    cout<<ans<<endl;
    return 0;
}

书(book.cpp)
Hazel有n本书,编号1为n到 ,叠成一堆。当她每次抽出一本书的时候,上方的书会因重力而下落,这本被取出的书则会被放置在书堆顶。
每次有pi的概率抽取编号为i的书。她每次抽书所消耗的体力与这本书在这堆中是第几本成正比。具体地,抽取堆顶的书所耗费体力值为1 ,抽取第二本耗费体力值为2 ,以此类推。
现在 想知道,在很久很久以后(可以认为几乎是无穷的),她每次抽书所耗费的体力的期望值是多少。
最终的答案显然可以表示成a/b的形式,请输出a*(b^-1)模1e9+7的值。
【输入格式】
第一行一个整数n
接下来n行,每行两个整数ai,bi,代表抽取第i本书的概率是ai/bi
保证所有书的概率和等于1
【输出格式】
输出一行一个整数,代表期望值
【输入样例1】
2
227494 333333
105839 333333
【输出样例1】
432679642
【输入样例2】
10
159073 999999
1493 142857
3422 333333
4945 37037
2227 111111
196276 999999
190882 999999
142721 999999
34858 999999
101914 999999
【输出样例2】
871435606
【数据规模与约定】
对于30%的数据,1<=n<=10。
对于100%的数据,1<=n<=1000,0<=ai<=bi,bi!=0。

题解:期望本人不太会,yy出来的,可以参考这一篇blog

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MOD=1e9+7;
int n;
ll a,b,p[1002];
ll fpow(ll a,ll b,ll p) {
    ll ret=1;
    while (b) {
        if (b&1) ret=ret*a%p;
        b>>=1,a=a*a%p;
    }
    return ret;
}
inline int read() {
    int x=0;char c=getchar();
    while (c<'0'||c>'9') c=getchar();
    while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x; 
}
/*
    ans=sigma(pi*E)
       =sigma(pi*(1+sigma(pj[j在i上面])))
       =sigma(pi*(1+sigma(pj/(pi+pj))))
*/
int main() {
    freopen("book.in","r",stdin);
    freopen("book.out","w",stdout);
    while (~scanf("%d",&n)) {
        for (int i=1;i<=n;++i)
            a=read(),b=read(),p[i]=a*fpow(b,MOD-2,MOD)%MOD;
        ll ans=0;
        for (int i=1;i<=n;++i) {
            ll sum=1;
            for (int j=1;j<=n;++j)
                if (i^j)
                    sum=(sum+p[j]*fpow((p[i]+p[j])%MOD,MOD-2,MOD)%MOD)%MOD;
            ans=(ans+p[i]*sum%MOD)%MOD;
        }
        cout<<ans<<endl;
    }
    return 0;
}
NOI(全国青少年信息学奥林匹克竞模拟的测试数据是指用于评测参选手的程序的输入和对应的输出。测试数据是非常重要的,因为它决定了参选手的程序能否正确地解决问题。 在NOI模拟,测试数据具有以下特点: 1.充分覆盖:测试数据应涵盖各种可能的输入情况,包括边界条件和极端情况。通过提供不同的测试数据,可以考察选手对问题的全面理解和解决能力。 2.随机性和均衡性:为了公平起见,测试数据应该是随机生成的,而不是针对某个特定算法或解法设计的。同时,测试数据应该是均衡的,即各种情况的概率应该大致相等,以避免偏向某些解法。 3.合理性和可行性:测试数据应该是合理和可行的,即符合题目要求的输入数据,并且是选手能够通过编写程序来处理的。测试数据应该考虑到程序的限制和时间复杂度,以充分测试选手的编程能力。 NOI模拟的测试数据通常由经验丰富的考题组负责生成。他们会根据题目的要求和限制,设计出一组合理、充分、随机和均衡的测试数据,以确保参选手的程序在各种情况下都能正确运行,并且能通过性能测试。 总之,测试数据在NOI模拟起到了至关重要的作用,它既考察了选手对问题的理解和解决能力,又提高了选手编程的技巧和效率。同时,合理和恰当的测试数据也是公平竞的保证,确保每个参选手有相同的机会和条件进行竞争。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值