2019-7-14 考试总结

A. 序列

首先,如果一个数列是等比数列并且公比$q!=1$的话,那么

  1. 对于它们中的每一个数,它都能被其他的任意一个数整除或者整除任意一个数。
  2. 并且他们不能互质,也就是$gcd!=1$。
  3. 不能有重复的数。

知道这个,这个题就基本上可以$AC$了,

理论复杂度基本上是$O(n^2)$,但是可以通过判断剪掉很多复杂度。

如果$q=1$,那么可以线性dp找最长重复序列。

如果$q!=1$,那么先枚举起点,再从起点往后枚举每个数,更新$ans$,

如果不满足那$3$个条件直接$break$。

丑陋的代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<set>
#define Maxn 1000050
#define Reg register
using namespace std;
const int L=1<<20|1;
char buffer[L],*S,*TT;
#define getchar() ((S==TT&&(TT=(S=buffer)+fread(buffer,1,L,stdin),S==TT))?EOF:*S++)
long long n,maxx,num[Maxn],dp[Maxn],ans=1;
inline long long max(long long x,long long y) {return x>y?x:y;}
inline long long min(long long x,long long y) {return x<y?x:y;}
inline long long read()
{
    Reg long long a=0,b=1;Reg char ch=getchar();
    while(ch<'0'||ch>'9') b=(ch=='-')?-1:1,ch=getchar();
    while(ch>='0'&&ch<='9') a=(a<<3)+(a<<1)+(ch^48),ch=getchar();
    return a*b;
}
inline long long gcd(Reg long long x,Reg long long y)
{
    if(x==y) return x;
    else if(x==0||y==0) return x+y;
    else return gcd(y,x%y);
}
int main()
{
//    freopen("text.in","r",stdin);
    n=read();
    for(Reg int i=1;i<=n;++i) num[i]=read();
    dp[1]=1;
    for(Reg int i=2;i<=n;++i)
    {
        if(num[i]==num[i-1]) dp[i]=dp[i-1]+1;
        else dp[i]=1;
        ans=max(ans,dp[i]);
    }
    for(Reg int i=1;i<=n-ans;++i)
    {
        Reg long long gcp;
        set<long long> q; q.clear();
        Reg long long l1=max(num[i],num[i+1]);
        Reg long long l2=min(num[i],num[i+1]);
        if(l1%l2!=0) continue; gcp=l1/l2;
        if(gcp==1) continue;
        q.insert(num[i]); q.insert(num[i+1]);
        if(q.size()!=2) continue;
        ans=max(ans,2);
        for(Reg int j=i+2;j<=n;++j)
        {
            set<long long>::iterator it;
            Reg long long l1=num[j],gpp=*--q.end();
            if(gpp==1) break;
            Reg int ov=1;
            for(it=q.begin();it!=q.end();++it)
            {
                Reg long long p=*it;
                if(p>l1)
                {
                    Reg long long lp=p/l1;
                    if(lp*l1!=p) {ov=0; break;}
                    else
                    {
                        Reg long long y=gcd(gpp,lp);
                        if(y!=gpp&&y!=lp) {ov=0; break;}
                        gpp=y;
                        if(gpp==1) {ov=0; break;}
                        continue;
                    }
                }
                else
                {
                    Reg long long lp=l1/p;
                    if(lp*p!=l1) {ov=0; break;}
                    else
                    {
                        Reg long long y=gcd(gpp,lp);
                        if(y!=gpp&&y!=lp) {ov=0; break;}
                        gpp=y;
                        if(gpp==1) {ov=0; break;}
                        continue;
                    }
                }
            }
            if(!ov) break;
            Reg long long y=gcd(gcp,gpp);
            if(y!=gcp&&y!=gpp||y==1) break;
            gcp=y;
            l1=q.size(); q.insert(num[j]); l2=q.size();
            if(l1==l2) break;
            ans=max(ans,j-i+1);
        }
    }
    printf("%lld",max(1,ans));
    return 0;
}
View Code

 

B. 熟练剖分(tree)

首先这个题要明白一个东西:$a/b+a/c≡a*(inv[b]+inv[c])  (mod p)$。

这个题暴力就可以做。

题目要求期望,那么我们可以求每种可能的概率,然后相乘,就得到期望。

对于每个节点,枚举它的每个儿子作为重链,然后再枚举所有儿子的可能的轻链的条数,更新这个节点。

根据上面的式子,我们可以直接将概率 ”相加“ 而不用通分,

最后在$root$节点求一下期望。

丑陋的代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#define Maxn 3050
#define mod 1000000007
#define Inv(x) (mi((x),mod-2,mod))
#define Reg register
using namespace std;
const int L=1<<20|1;
char buffer[L],*S,*TT;
#define getchar() ((S==TT&&(TT=(S=buffer)+fread(buffer,1,L,stdin),S==TT))?EOF:*S++)
int n,k,root,du[Maxn];
long long dp[Maxn],p[Maxn][Maxn],vis[Maxn][Maxn];
vector<vector<int> > son(Maxn),vp(Maxn);
inline long long max(long long x,long long y) {return x>y?x:y;}
inline long long read()
{
    Reg long long a=0,b=1;Reg char ch=getchar();
    while(ch<'0'||ch>'9') b=(ch=='-')?-1:1,ch=getchar();
    while(ch>='0'&&ch<='9') a=(a<<3)+(a<<1)+(ch^48),ch=getchar();
    return a*b;
}
inline long long mi(Reg long long x,Reg long long y,Reg long long p)
{
    Reg long long ans=1,base=x;
    while(y)
    {
        if(y&1) ans=(ans*base)%p;
        base=(base*base)%p;
        y>>=1;
    }
    return ans;
}
inline void dfp(Reg int x,Reg int child,Reg int zchi,Reg long long cnt,Reg long long poz)
{
    if(child==son[x].size())
    {
        p[x][cnt]=(p[x][cnt]+poz*Inv(son[x].size()))%mod;
        if(!vis[x][cnt])
        {
            vis[x][cnt]=1;
            vp[x].push_back(cnt);
        }
        return;
    }
    Reg int k=son[x][child];
    for(Reg int i=0;i<vp[k].size();++i)
    {
        if(child!=zchi) dfp(x,child+1,zchi,max(cnt,vp[k][i]+1),(p[k][vp[k][i]]*poz)%mod);
        else dfp(x,child+1,zchi,max(cnt,vp[k][i]),(p[k][vp[k][i]]*poz)%mod);
    }
    return;
}
inline void dfs(Reg int x)
{
//    cout<<x<<endl;
    for(Reg int i=0;i<son[x].size();++i) dfs(son[x][i]);
    for(Reg int i=0;i<son[x].size();++i)  //i是重儿子 概率1/son[x].size()
        dfp(x,0,i,0,1);
    if(!son[x].size())
    {
        p[x][0]=1;
        vp[x].push_back(0);
        vis[x][0]=1;
    }
    return;
}
int main()
{
//    freopen("text.in","r",stdin);
    n=read();
    for(Reg int i=1,k;i<=n;++i)
    {
        k=read();
        for(Reg int j=1,x;j<=k;++j)
        {
            x=read();
            son[i].push_back(x);
            ++du[x];
        }
    }
    for(Reg int i=1;i<=n;++i) if(!du[i]) root=i;
    dfs(root);
    Reg long long anp=0;
    for(Reg int i=0;i<vp[root].size();++i)
        anp=(anp+p[root][vp[root][i]]*vp[root][i])%mod;
    printf("%lld",anp);
    return 0;
}
View Code

 

posted @ 2019-07-17 16:19  Milk_Feng  阅读(100)  评论(0编辑  收藏  举报