zoukankan      html  css  js  c++  java
  • 测试72.思维好题


    T0:难度不是太大,关键思维要灵活。

    考试状态不是太好,改题时觉得没那么难。是可以想的。

    T1:语文题。题意理解要去猜测含义。找特殊的地方。

    卡特兰数,DP可做。

    合法指全部匹配。

    发现左边右边必须放的括号数一定。其余可以分配。

    枚举给左边x个(,y个),则右边也已确定,

    然后卡特兰即可。

    Code

    #include<bits/stdc++.h>
    #define F(i,a,b) for(int i=a;i<=b;++i)
    #define LL long long
    #define pf(a) printf("%lld ",a)
    #define phn puts("")
    using namespace std;
    /** 特判题*/
    #define int LL
    int n,m;
    #define N 100010
    char s[N];
    const int mod=1e9+7;
    int jc[N],inv[N];
    int qpow(int x,int k){int s=1;for(;k;k>>=1,x=x*x%mod)if(k&1)s=s*x%mod;return s;}
    int MO(int x){return x<mod?x:x-mod;}
    void Parise(){
            jc[0]=1;const int maxn=5e3;
            F(i,1,maxn)jc[i]=jc[i-1]*i%mod;
            inv[maxn]=qpow(jc[maxn],mod-2);
            for(int i=maxn;i>0;--i)inv[i-1]=inv[i]*i%mod;
    }
    int C(int x,int y){
            if(x<y)return 0;
            if(x==y||y==0)return 1;
            return jc[x]*inv[y]%mod*inv[x-y]%mod;
    }
    int Cat(int x,int y){
            return MO(C(x+y,y)-C(x+y,y-1)+mod);
    }
    signed main(){
            Parise();
            scanf("%lld%lld%s",&n,&m,s+1);
            int t=0,a=0,b=0;
            F(i,1,m){
                    if(s[i]=='(')++t;
                    else if(t>0)--t;
                    else ++a;
            }
            t=0;
            for(int i=m;i>0;--i){
                    if(s[i]==')')++t;
                    else if(t>0)--t;
                    else ++b;
            } 
            LL ans=0;
            int res=n-m-a-b,resgl=res>>1;
            if(res<0||res&1){
                    return puts("0"),0;
            }
            F(x,0,resgl){
                    F(y,0,x){
                            ans=(ans+Cat(a+x,y)*Cat(b+resgl-y,resgl-x))%mod;
                    }
            }
            ans=(ans%mod+mod)%mod;
            printf("%lld
    ",ans);
    }
    /*
    g++ 1.cpp
    ./a.out
    2000 1 (
    4 4 (())
    4 3 (((
    */
    View Code

    T2DP好题。状态定义好题。

    两种操作,*2+1,求质因数分解中2的次数的期望。

    题意转化:转化为2进制,求最低位的1,lowbit在哪位的期望。

    考试想的数位DP,但是很难写。

    改变状态定义是打开思路,或优化DP的手段。

    *2好处理,关键+1会进位。

    所以状态要能够描述进位。

    如果从最低位开始记录连续的1的个数,当加多了以后会对高位产生影响,

    但是高位没有记录。

    N<=200,+1的影响有限,最多+200。加到第9位最多一次。

    因为高位可能有连续的1,所以不能只记录后9位。

    由于要向高位进位,记录高位(9th开始)连续的1的信息。

    开始没想到为什么要记录了连续的0.

    因为如果后8位为0,lowbit在高位。记录连续0可以知道lowbit

    那么f[n][s][j][k],  f[200][1<<8][200+30][0/1]即可.

    O(n*(n+30)*(2^8))

    整理一下,看看状态是怎么描述这个过程的。

    +1进位少,因为高位几乎不受影响,并且根据n<=200可以知道+1影响的范围,所以关注的只有低位是谁,和对高位的进位。

    好的状态定义只关注需要关注的,从而描述出整个过程,建立出模型。

    只关注低位也是一种类似取余的思想。

    Code

    #include<bits/stdc++.h>
    #define F(i,a,b) for(int i=a;i<=b;++i)
    #define LL long long
    #define pf(a) printf("%d ",a)
    #define PF(a) printf("%lld ",a)
    #define phn puts("")
    using namespace std;
    int a,n; double P,ans;
    double f[202][1<<8][1<<8][2];
    #define DP f[i][s][j]
    int bin[1<<8];
    const double eqs=1e-4;
    int main(){
        scanf("%d%d%lf",&a,&n,&P);P/=100;
        const int low=(1<<8)-1;
        int c=1,t=(a>>8)&1;
        for(int i=9;a>>i;++i){
            if(((a>>i)&1)==t){/** 第9位开始*/
                ++c;
            }else break;
        }
        f[1][a&low][c][t]=1.0;
        F(i,1,n)F(s,0,low)F(j,1,i+30){
            t=s+1;
            if(t<=low){
                F(k,0,1)f[i+1][t][j][k]+=DP[k]*(1-P);
            }else{
                f[i+1][t&low][1][1]+=DP[0]*(1-P);
                f[i+1][t&low][j][0]+=DP[1]*(1-P);
            }
            t=(s>>7)&1;
            F(k,0,1){
                if(t==k){
                    f[i+1][(s<<1)&low][j+1][t]+=DP[k]*P;
                }else{
                    f[i+1][(s<<1)&low][1][t]+=DP[k]*P;
                }
            }
        }
        double ans=0;
        for(int i=1,j=1;j<=8;++j,i<<=1)bin[i]=j;
        F(i,n+1,n+1)F(s,0,0)F(j,1,n+30){
            ans+=DP[0]*(7+j+1)+DP[1]*8;
        }
        F(i,n+1,n+1)F(s,1,low)F(j,1,n+30){
            ans+=(DP[0]+DP[1])*(bin[s&-s]-1);
        }
        printf("%.8lf
    ",ans);
    }
    /*
    g++ 2.cpp
    ./a.out
    1 1 50
    5 3 0
    5 3 25
    */
    View Code

    T3

    发现类似树,图论这些找性质的题不是总能想出来。没有思路时去找性质。从特殊到一般拓展。

    手模,发现奇环一定不行。

    判定奇环的技巧:黑白染色。

    然后就不会了。。。

    考虑每一个联通块。先考虑简单环。最长链是直径。

    图的直径是最长的两点间最短路。

    发现多个环套在一起,结论成立。

    对于多个联通块,两条链可以合并,长度为总和。

    考虑求直径。这里开始想麻烦了。观察数据范围,n*m<=1e8.

    直接枚举所有点bfs.复杂度是没问题的。

    Code

    #include<bits/stdc++.h>
    #define F(i,a,b) for(int i=a;i<=b;++i)
    #define pf(a) printf("%d ",a)
    #define phn puts("")
    using namespace std;
    /**
    判奇环:黑白染色。
    联通块直径:所有点bfs。
    
    SB错误
    应该输出ans,而不是mx
    变成了最后一个联通块的直径。。。
    */
    int n,m;
    #define N 2002
    #define M 400010
    int to[M],fir[M],head[N],cnt;
    char vis[N];
    int sta[N],top;
    int dl[N<<1],dis[N];
    void add(int x,int y){to[++cnt]=y;fir[cnt]=head[x];head[x]=cnt;}
    int BW(int x){
        for(int i=head[x],v;i;i=fir[i]){
            if(vis[v=to[i]]==-1){
                vis[v]=vis[x]^1;
                if(!BW(v))return 0;
            }
            else if(vis[v]==vis[x])return 0;
        }
        return 1;
    }
    void Push(int x){
        sta[++top]=x;vis[x]=1;
        for(int i=head[x],v;i;i=fir[i])if(!vis[v=to[i]])Push(v);
    }
    int getdis(int x){
        int hd=1,tl=0,mx=0;
        memset(dis,0x3f,sizeof(dis));
        dl[tl=1]=x;dis[x]=0;
        while(hd<=tl){
            int u=dl[hd++];
            for(int i=head[u],v;i;i=fir[i])
                if(dis[v=to[i]]>dis[u]+1)
                {    mx=max(mx,dis[v]=dis[u]+1),dl[++tl]=v;}
        }    
        return mx;
    }
    int main(){
        scanf("%d%d",&n,&m);
        int x,y;
        F(i,1,m)scanf("%d%d",&x,&y),add(x,y),add(y,x);
        int ok=1;
        memset(vis,-1,sizeof(vis));
        F(i,1,n){
            if(vis[i]==-1){
                vis[i]=1;
                if(!BW(i)){ok=0;break;}
            }
        }    
        if(!ok)return puts("-1"),0;
        memset(vis,0,sizeof(vis));
        int ans=0,mx;
        F(i,1,n)if(!vis[i]){
            Push(i);
            mx=0;
            F(j,1,top)mx=max(mx,getdis(sta[j]));
            ans+=mx;top=0;
        }
        printf("%d
    ",ans);
    }
    /*
    g++ 3.cpp
    ./a.out
    5 4
    1 2
    2 3
    3 4
    3 5
    
    4 6
    1 2
    2 3
    1 3
    3 4
    2 4
    1 4
    */
    View Code
  • 相关阅读:
    连接SDE数据库hl3292修改已解决
    ORACLE 10g 安装
    SharpMap相关的一些博客和网站
    Delphi 学习之函数 ②扩展的日期时间操作函数
    Delphi学习之函数 ⑾进制函数及过程
    Delphi学习之函数 ① 扩展的字符串操作函数
    html 初次接触html学习【1】
    Delphi 学习之函数 ③ 扩展的位操作函数
    Delphi学习之函数 ⑨汉字拼音功能函数
    Delphi学习之函数 ④扩展的文件及目录操作函数
  • 原文地址:https://www.cnblogs.com/seamtn/p/11670354.html
Copyright © 2011-2022 走看看