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$树,维护一下历史版本的答案,每次统计完答案在加入字符串,最后一块输出即可

  • 相关阅读:
    python3 练习题 day04
    python3 装饰器
    python3 生成器和生成器表达式
    python3 列表/字典/集合推导式
    python3 迭代器
    python3 day04 大纲
    ES6 的数值扩展
    ES6中的解构赋值
    ES6中 let与const 的区别
    react的基本配置安装及使用babel
  • 原文地址:https://www.cnblogs.com/si-rui-yang/p/9901009.html
Copyright © 2011-2022 走看看