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
#include
#include
#include
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;iint 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;iprintf("%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
#include
#include
#include
#include
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?ida.w;
    }
};
set 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<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
#include
#include
#include
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<return 0;
}

你可能感兴趣的:(OI-模拟赛)