zoukankan      html  css  js  c++  java
  • 20181103 考试记录

    题目

    这是$NOIP$模拟赛(---)

    T1:

    想的太复杂了,开头$1$个小时认为此题不可做,所以到最后也懒得打$O(n)$的方法,只打了$O(n^2)$的东西

    我的做法:

    先把数据的图建出来,然后查看对于每个列是否没产生矛盾

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<map>
    #include<algorithm>
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    int vis[300001],n,has[300001],a[300001],b[300001],c[300001],lb[300001],lc[300001];
    struct node{
        int u,v,nex;
    }x[1010001];
    int ma[300001];
    int cnt,head[300001];
    void add(int u,int v){
        x[cnt].u=u,x[cnt].v=v,x[cnt].nex=head[u],head[u]=cnt++;
    }
    int ba[300001],ca[300001],ans;
    int bb[101],cc[101],minn=2<<30-1,aa[101],book[101];
    void dfs(int pos){
        if(pos>=1&&pos<=n) ma[++ma[0]]=pos;
        for(int i=head[pos];i!=-1;i=x[i].nex){
            if(!vis[x[i].v]){
                vis[x[i].v]=1;
                dfs(x[i].v);
            }
        }
    }
    void check(){
        int ans=0;
        aa[0]=0,bb[0]=0,cc[0]=0;
        for(int i=1;i<=n;i++){
            if(book[i]==1){
                aa[++aa[0]]=a[i];
                bb[++bb[0]]=b[i];
                cc[++cc[0]]=c[i];
                ans++;
            }
        }
        sort(aa+1,aa+aa[0]+1);
        sort(bb+1,bb+bb[0]+1);
        sort(cc+1,cc+cc[0]+1);
        for(int i=1;i<=aa[0];i++){
            if(aa[i]==bb[i]&&aa[i]==cc[i]&&bb[i]==cc[i]){
                continue;
            }return ;
        }
        minn=min(minn,n-ans);
        return;
    }
    void dfs1(int pos){
        if(pos==n+1){
            check();return;
        }
        book[pos]=1;
        dfs1(pos+1);
        book[pos]=0;
        dfs1(pos+1);
        book[pos]=0;
    }
    
    int main(){
    //     freopen("avogadro.in","r",stdin);
    //     freopen("avogadro.out","w",stdout);
        memset(head,-1,sizeof(head));
        n=read();
        for(int i=1;i<=n;i++) a[i]=read(),has[a[i]]=i;
        for(int i=1;i<=n;i++) b[i]=read(),lb[i]=has[b[i]],add(i+n,lb[i]);
        for(int i=1;i<=n;i++) c[i]=read(),lc[i]=has[c[i]],add(i+2*n,lc[i]);
        if(n<=10){
            dfs1(1);
            cout<<minn;
            return 0;
        }
        for(int i=1;i<=n;i++) add(i,i+n),add(i,i+2*n);
        for(int i=1;i<=n;i++){
            ma[0]=0;
            memset(ba,0,sizeof(ba)),memset(ca,0,sizeof(ca));
            memset(vis,0,sizeof(vis));
            vis[i]=1;
            dfs(i);
            for(int j=1;j<=ma[0];j++) ba[b[ma[j]]]++;
            for(int j=1;j<=ma[0];j++) ca[c[ma[j]]]++;
            for(int j=1;j<=ma[0];j++){
                if(ba[b[ma[j]]]!=1||ca[c[ma[j]]]!=1){
                    ans++;
                    break;
                }
            }
        }
        cout<<ans;
        return 0;
    }
    /*
    9
    1 3 5 9 8 6 2 4 7
    2 1 5 6 4 9 3 4 7
    3 5 1 9 8 6 2 8 7
    */
    View Code

    别人的做法:

    垃圾搜索。其实要抓住第一列是不重复的数这一特点去解题。若第$2,3$列有没有出现而在第$1$行出现的时候,则这一列必须删去,有可能又有不存在的数,就再去删除,时间复杂度$O(n)$,因为每个列只会最多删去一次。并且可以去先按照第一行排序,这样就方便查询了。

    正确性:因为有小于$0$的就必有$leq 2$的数,而这就恰好可以去进行搜索了,但是如果去先统计$leq 2$的点,就会产生冲突,因为不知道该删哪个

    T2:

    好像以前讲过类似的题,但是却不会写,自己的暴力也还挂了,看到$n leq 9$想到什么,搜索  状压啊,但在考场上还不会写。

    我们设$dp(i,S)$表示已经要决策到第i条边,点的集合划分为$S$($n!$状压),每个点都能在当前的集合中互相到达的概率是多少。

    所以分两种情况讨论:
    若第i条边是好的,则$dp(i,合并当前的2个集合)=dp(i-1,S)*(1-{p_i})$

    若是不好的,则$dp(i,S)=dp(i-1,S)*(p_i)$

    主要是怎么去写那个$S$

    #include<algorithm>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<ctime>
    #include<iomanip>
    #include<iostream>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #define rep(i,x,y) for(register int i=(x);i<=(y);i++)
    #define dwn(i,x,y) for(register int i=(x);i>=(y);i--)
    #define maxn 10
    #define maxm 90
    #define maxs 363000
    using namespace std;
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)&&ch!='-')ch=getchar();
        if(ch=='-')f=-1,ch=getchar();
        while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
        return x*f;
    }
    void write(int x)
    {
        int f=0;char ch[20];
        if(!x){putchar('0'),putchar('
    ');return;}
        if(x<0)x=-x,putchar('-');
        while(x)ch[++f]=x%10+'0',x/=10;
        while(f)putchar(ch[f--]);
        putchar('
    ');
    }
    int mul[maxn],tmp[maxn],tmp2[maxn],eu[maxm],ev[maxm],n,m;
    long double ew[maxm],p[2][maxs];
    int gx(int x,int y){return (x-1)*mul[y-1];}
    void bac(int S)
    {
        dwn(i,n,1)
        {
            tmp[i]=S/mul[i-1]+1;
            S%=mul[i-1];
        }
    }
    int gets()
    {
        int s=0;
        rep(i,1,n)
        {
            s+=gx(tmp2[i],i);
        }
        return s;
    }
    /*
    int maxs;
    void getst(int x)
    {
        if(x==10)
        {
            int s=0;
            rep(i,1,9)
            {
                s+=gx(fa[i],i);
            }
            if(yes[s]){cout<<s<<"nooooooo";exit(0);}
        //    else cout<<"+"<<s<<endl;
            bac(s);
            yes[s]=1;
            maxs=max(maxs,s);
            return;
        }
        rep(i,1,x)
        {
            fa[x]=i;
            getst(x+1);
        }
    }*/
    int main()
    {
        freopen("connect.in","r",stdin);
        freopen("connect.out","w",stdout);
        mul[0]=1;
        rep(i,1,9)mul[i]=mul[i-1]*i;
        //getst(1);
        //cout<<maxs;
        n=read(),m=read();
        rep(i,1,m)
        {
            eu[i]=read(),ev[i]=read();
            if(eu[i]>ev[i])swap(eu[i],ev[i]);
            double w;scanf("%lf",&w);
            ew[i]=w;
        }
        rep(i,1,n)tmp2[i]=i;
        int nows=gets();
        p[0][nows]=1.0;
        //cout<<nows<<endl;
        rep(i,1,m)
        {
            //cout<<"i:"<<i<<endl;
            int now=i&1,pre=now^1;
            rep(u,0,nows)p[now][u]=0;
            rep(u,0,nows)
            {
                if(p[pre][u]==0.0000)continue;
                bac(u);//cout<<"tmp:"<<p[i][u]<<endl;
                //rep(j,1,n)cout<<tmp[j]<<" ";cout<<endl;
                int ss=tmp[eu[i]],tt=tmp[ev[i]];
                if(ss==tt){p[now][u]+=p[pre][u];continue;}
                if(ss>tt)swap(ss,tt);
                rep(j,1,n)
                {
                    if(tmp[j]==tt)tmp2[j]=ss;
                    else tmp2[j]=tmp[j];
                }
                int nxt=gets();
            //    cout<<"nxt:";
                //rep(j,1,n)cout<<tmp2[j]<<" ";
                //cout<<endl;
                p[now][nxt]+=p[pre][u]*(1.0-ew[i]);        
                p[now][u]+=p[pre][u]*ew[i];
                //cout<<p[i][nxt]<<endl;
            }
        }
        double ans=p[m&1][0];
        printf("%.3lf",ans);
        return 0;
    }
    syf

    T3:斜率优化$dp$,但是没有学,所以留坑待补

    $score:60+40+40=140$这分数是要完的节奏啊

    接下来的是CXM讲课的几道题

    T1:

    平面上有$n leq 3 imes 10^5$的店,坐标$leq 10^5$,点上有能量,且只能往直右或直上走,每走一次需要有$k$的能量($k leq 10^3$),问最大能量

     我们只要将怎样去快速转移达到就行了,所以我们采取从下到上,从左往右的顺序去$dp$,每一行内的答案可以去记录,每一列的答案可以用个表去更新,记录

    T2:

    有$n$个与$m$个单词$(leq 3 imes 10^5)$,每个单词$30$个字符,问每个单词的暴力查找次数($you$ $guess$ 这是什么意思)

    建一棵$Trie$树,若$m$中的一个单词$p$在$n$中没有出现过,那么答案就很好统计,否则,我们可以都扫描过一遍,然后看一看是$n$中第几个单词,然后在建一棵$Trie$树,维护一下历史版本的答案,每次统计完答案在加入字符串,最后一块输出即可

  • 相关阅读:
    HDU 5313 bitset优化背包
    bzoj 2595 斯坦纳树
    COJ 1287 求匹配串在模式串中出现的次数
    HDU 5381 The sum of gcd
    POJ 1739
    HDU 3377 插头dp
    HDU 1693 二进制表示的简单插头dp
    HDU 5353
    URAL 1519 基础插头DP
    UVA 10294 等价类计数
  • 原文地址:https://www.cnblogs.com/si-rui-yang/p/9901009.html
Copyright © 2011-2022 走看看