7/28-7/29 期望+思维+后缀数组+ST表

Posted 钟钟终

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了7/28-7/29 期望+思维+后缀数组+ST表相关的知识,希望对你有一定的参考价值。

期望的概念:
E(X+Y)=E(X)+E(Y) 因此可根据线性的可加性做题
在条件概率中,一个事件发生的概率固定

每日一题

Game (20上海ICPC热身赛)

类型:期望题,未与dp、数学结合
思路:
1.长度为n的序列中,存在多少互质的组合cnt
2.将n分成奇偶判断,若为奇数,则会产生(n-1)/2次消去,每次概率为cnt/C(n,2);
若为偶数,则会产生n/2次消去,每次概率为cnt/C(n,2)

#include<bits/stdc++.h>
#define int long long
#define endl '\\n'
#define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)

using namespace std;
const int N=5e5+5;
const int mod=1e9+7;
int n;
int fac[N];
int fastpow(int a,int b)

    int res=1;
    while(b)
    
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    
    return res;

int getinv(int a) //求逆元

    return fastpow(a,mod-2)%mod;

int C(int n,int m)  //C(n,m)

    return ((fac[n]*getinv(fac[m])%mod)*(getinv(fac[n-m])%mod))%mod;


signed main()

    IOS;
    cin>>n;
    int cnt=0;
    for(int i=1;i<n;i++)
    
        for(int j=i+1;j<=n;j++)
            if(__gcd(i,j)==1)   cnt++;
    
    if(n%2)
    
        int g=__gcd(cnt,n);
        cout<<cnt/g<<"/"<<n/g<<endl;
    
    else
    
        int g=__gcd(cnt,n-1);
        cout<<cnt/g<<"/"<<(n-1)/g<<endl;
    
    return 0;


Music Game 五一集训派对day2

类型:数学+期望的结合
思路:
1.处理出任意段事件发生的概率;在处理出不同长度m幂次方的值。
2.根据时间期望的可加性,枚举不同长度发生的期望值进行累加。

#include<bits/stdc++.h>
#define int long long
#define endl '\\n'
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)

using namespace std;
const int N=5e3+5;
const int mod=1e9+7;
int n,m,p[N],mul[N],pre[N][N];
int fastpow(int a,int b)

    int res=1;
    while(b)
    
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    
    return res;

int getinv(int a) //求逆元

    return fastpow(a,mod-2)%mod;


signed main()

    IOS;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        cin>>p[i],mul[i]=fastpow(i,m);
    int inv=getinv(100);
    p[0]=p[n+1]=0;
    for(int i=1;i<=n;i++)   //不同区间段成功的概率
    
        pre[i][i]=p[i]*inv%mod;
        for(int j=i+1;j<=n;j++)
            pre[i][j]=pre[i][j-1]*(p[j]*inv%mod)%mod;
    
    int ans=0;
    for(int i=0;i<=n;i++)
    
        for(int j=i+2;j<=n+1;j++)
        
            ans+=pre[i+1][j-1]*mul[j-i-1]%mod*(100-p[i])%mod*inv%mod*(100-p[j])%mod*inv%mod;
            ans%=mod;
        
    
    cout<<ans<<endl;
    return 0;


后缀数组

P4051 [JSOI2007]字符加密

思路:将字符串扩大两倍,在进行后缀数组的排序。证明与题意处理方式等价:
1.abcab中ab在abcab前面,题意中ababc在abcab前面;若扩大两倍为abcababcab,则ababcab在abcababcab前面,后面多余并不影响
2.转为为了sa的裸题

#include <bits/stdc++.h>
#define int long long
#define endl '\\n'

using namespace std;
const int N=1e6+5;
const int mod=1e9+7;
int n,k;
int rk[N],rk2[N];   //以i开头后缀的排名
char s[N];
int sa[N];   //表示sa[i]表示排名i的后缀的开头下标

//求解各个以i为起始下标的后缀字符串的排名
bool cmp(int i,int j)

    if(rk[i]!=rk[j])
        return rk[i]<rk[j];
    int ri=(i+k<=n ? rk[i+k]:-1);
    int rj=(j+k<=n ? rk[j+k]:-1);
    return ri<rj;

void getsa(int n,char *str)

    for(int i=1;i<=n;i++)
        sa[i]=i,rk[i]=s[i];  //利用ASCLL码
    for(k=1;k<=n;k*=2)
    
        sort(sa+1,sa+1+n,cmp);
        rk2[sa[1]]=1;
        for(int i=2;i<=n;i++)
            rk2[sa[i]]=rk2[sa[i-1]]+cmp(sa[i-1],sa[i]);
        for(int i=1;i<=n;i++)
            rk[i]=rk2[i];
    


int ht[N];   //维护数组rk相邻两个后缀的lcp(i-1和i的最长公共前缀)
void getht(int n,char *s)

    for(int i=1;i<=n;i++)
        rk[sa[i]]=i;
    int h=0;
    ht[1]=0;
    for(int i=1;i<=n;i++)
    
        int j=sa[rk[i]-1];
        if(h>0)
            h--;
        for(;j+h<=n&&i+h<=n;h++)
            if(s[j+h]!=s[i+h])
                break;
        ht[rk[i]]=h;
    

/*
int top,ll[N],rr[N],sk[N],ans;
int cal(int n,char *s)

    getsa(n,s);
    getht(n,s);
    top=1,sk[1]=1;
    for(int i=2;i<=n;i++)
    
        while(top&&ht[sk[top]]>ht[i])
            rr[sk[top]]=i,top--;
        ll[i]=sk[top];
        sk[++top]=i;
    
    while(top)
        rr[sk[top]]=n+1,top--;
    int res=0;
    for(int i=2;i<=n;i++)
        res+=(i-ll[i])*(rr[i]-i)*ht[i];
    return res;
*/

signed main()

    cin>>(s+1);
    n=strlen(s+1);
    for(int i=1;i<=n;i++)
        s[i+n]=s[i];
    n*=2;
    getsa(n,s);
    for(int i=1;i<=n;i++)
        if(sa[i]<=n/2)
        cout<<s[sa[i]+n/2-1];
    cout<<endl;
	return 0;


思维

A. Color the Picture

思路:
1.要保证一个颜色至少三个相邻和它有相同的颜色,则保证该颜色至少能涂两列
2.若m为技术的情况,则需找到至少一种颜色能涂三列
3.n和m的数值调换的情况也要考虑到

#include<bits/stdc++.h>
#define int long long
#define endl '\\n'
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)

using namespace std;
const int N=5e5+5;
const int mod=1e9+7;
int n,m,k,a[N];
int f,f1,ans;
void check(int n,int m)

    ans=0;
    for(int i=1;i<=k;i++)
    
        if(a[i]/n>=2)
        
            if(a[i]/n>=3)
                f1=1;
            ans+=a[i]/n;
        
    
    if(m%2)
    
        if(ans>=m&&f1)
            f=1;
    
    else
        if(ans>=m)
            f=1;

signed main()

    IOS;
    int t;cin>>t;
    while(t--)
    
        f=f1=0;
        cin>>n>>m>>k;
        for(int i=1;i<=k;i++)
            cin>>a[i];
        check(n,m);
        swap(n,m);
        check(n,m);
        if(f)
            cout<<"YES"<<endl;
        else
            cout<<"NO"<<endl;
    
    return 0;


ST表
1.基于倍增思想,可做到O(n*logn)的预处理,O(1)的查询
2.解决指定运算的区间询问
模板:

//ST表
int lg[N];  //记录log2N的整数值
int st[N][30];  //以i为左端点长度为2的j次方的序列所求最值
void ST(int n)

    lg[1]=0;
    for(int i=2;i<=n;i++)
        lg[i]=lg[i-1]+(1<<(lg[i-1]+1)==i);
    for(int i=1;i<=n;i++)
        st[i][0]=a[i];
    for(int j=1;(1<<j)<=n;j++)
    
        for(int i=1;i+(1<<j)-1<=n;i++)
            st[i][j]=max(st[i][j-1],st[i+(1<<j-1)][j-1]);
    

int sch(int l,int r)

    if(l>r)
        return 0;
    int k=lg[r-l+1];
    return max(st[l][k],st[r-(1<<k)+1][k]);

D. Rorororobot

题意:n行m列的网格中,每列下方中a[i]个格子被阻塞,可以往上下左右四个方向移动,不可出边界或碰到阻塞格子,不计次数,能否正好移动到重点。

思路:
1.先判断起点和终点间的行可否移动到同一行,每次移动需走k步
2.同理,列格子可否移动到同一列
3.每一列阻塞格子的最大值不可超过最终到达的起点值

#include<bits/stdc++.h>
#define int long long
#define endl '\\n'
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define y1 y11
using namespace std;
const int N=5e5+5;
const int mod=1e9+7;
int n,m,a[N];
int x1,y1,x2,y2,k;

//ST表
int lg[N];  //记录log2N的整数值
int st[N][30];  //以i为左端点长度为2的j次方的序列所求最值
void ST(int n)

    lg[1]=0;
    for(int i=2;i<=n;i++)
        lg[i]=lg[i-1]+(1<<(lg[i-1]+1)==i);
    forPOJ 3693 Maximum repetition substring(后缀数组+ST表)

BZOJ 3230 相似子串 | 后缀数组 二分 ST表

UVA 11475 Extend to Palindrome(后缀数组+ST表)

2019 CCPC 网络赛第三题 K-th occurrence 后缀数组+划分树+ST表+二分

URAL 1297 Palindrome(后缀数组+ST表)

hdu 6704 K-th occurrence 二分 ST表 后缀数组 主席树