zoukankan      html  css  js  c++  java
  • [noip][2016]

    Day1T1

    思路:

    非常简单的一个模拟

    代码:

    #include<cstdio>
    #include<iostream>
    using namespace std;
    const int N=1e5+100;
    int a[N],n,m,cr[N];
    char s[N][50];
    int main() {
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;++i) {
            scanf("%d",&cr[i]);
            cin>>s[i];
        }
        int ans=0;
        for(int i=1;i<=m;++i) {
            int x,y;
            scanf("%d%d",&x,&y);
            if(x==cr[ans])
                ans=(ans-y%n+n)%n;
            else
                ans=(ans+y%n)%n;
        }
        cout<<s[ans];
        return 0;
    }
    

    Day1T3

    思路:

    并不是很难得一个期望dp(虽然一开始没做出来233),首先跑一边floyd找出最短路,用f[i][j][0/1]表示前i短时间,换了j次,第i段时间换(1)还是不换(0)的最小耗费。

    如果不换,那么当前最有花费就是第i-1短时间换(就用前一个换的情况加上换之后的教室到当前教室的距离,当然还要考虑期望,有k[i-1]的概率会换成功,有(1-k[i-1])的概率不成功)或者不换(就直接用前一个不换的情况加上前一个教室到当前教室的距离)中更优秀的那个。即

    f[i][j][0]=min(f[i-1][j][0]+a[c[i-1]][c[i]],f[i-1][j][1]+a[d[i-1]][c[i]]*k[i-1]+a[c[i-1]][c[i]]*(1-k[i-1]))
    

    如果换,那么就比较麻烦一点,但是只要慢慢想出所有情况就可以了。

    首先如果前一个不换,那么就有k[i]的概率是从c[i-1] (不换情况下的教室)到d[i] (换之后的教室)。有(1-k[i])的概率是从c[i-1]到c[i]。所以

    f[i][j][1]=min(f[i][j][1],f[i-1][j-1][0]+(a[c[i-1]][d[i]])*k[i]+(a[c[i-1]][c[i]])*(1-k[i]))
    

    如果前一个也换的换的话,那么有k[i]k[i-1]的概率是从d[i-1]到d[i],有k[i](1-k[i-1])的概率是从c[i-1]到d[i],有(1-k[i])k[i-1]的概率是从d[i-1]到c[i],有(1-k[i-1])(1-k[i-1])的概率是从c[i-1]到c[i],所以

    f[i][j][1]=min(f[i][j][1], f[i-1][j-1][1]+(a[d[i-1]][d[i]])*k[i]*k[i-1]+a[d[i-1]][c[i]]*(1-k[i])*k[i-1]+a[c[i-1]][d[i]]*k[i]*(1-k[i-1])+a[c[i-1]][c[i]]*(1-k[i])*(1-k[i-1]))
    

    代码:

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    using namespace std;
    const int N=310,M=2000+10;
    const double INF=999999999;
    int n,m,V,E;
    int c[M],d[M];
    double a[M][M];
    double K[M],f[M][M][2];
    inline void init() {
        cin>>n>>m>>V>>E;
        for(int i=1;i<=V;++i) for(int j=1;j<=V;++j) a[i][j]=INF;
        for(int i=1;i<=n;++i)
            cin>>c[i];
        for(int i=1;i<=n;++i) 
            cin>>d[i];
        for(int i=1;i<=n;++i) 
            cin>>K[i];
        for(int i=1;i<=E;++i) {
            int x,y;
            cin>>x>>y;
            double z;
            cin>>z;
            a[x][y]=a[y][x]=min(a[x][y],z);
        }
    }
    inline void floyd() {
        for(int i=1;i<=V;++i) a[i][i]=0;
        for(int k=1;k<=V;++k) 
            for(int i=1;i<=V;++i) 
                for(int j=1;j<=V;++j) 
                    if(a[i][j]>a[i][k]+a[k][j])
                        a[i][j]=a[i][k]+a[k][j];
    }  
    int main() {
        ios::sync_with_stdio(false);
        init();
        floyd();
        if(m==0) {
            double mans=0;
            for(int i=2;i<=n;++i)
                mans+=a[c[i-1]][c[i]];
            printf("%.2f
    ",mans);
            return 0;
        }
        /*for(int i=1;i<=V;++i) {
            for(int j=1;j<=V;++j) {
                printf("%.0f ",a[i][j]);
            }
            printf("
    ");
        }*/
        for(int i=1;i<=n;++i) 
            for(int j=0;j<=m;++j)
                f[i][j][1]=f[i][j][0]=INF;
            f[1][1][1]=0;
            f[1][0][0]=0;
        for(int i=2;i<=n;++i) {
            for(int j=0;j<=min(m,i);++j) {
                f[i][j][0]=min(f[i-1][j][0]+a[c[i-1]][c[i]],f[i-1][j][1]+a[d[i-1]][c[i]]*K[i-1]+a[c[i-1]][c[i]]*(1-K[i-1]));
                if(j!=0)
                f[i][j][1]=min(f[i-1][j-1][0]+a[c[i-1]][d[i]]*K[i]+a[c[i-1]][c[i]]*(1-K[i]),f[i-1][j-1][1]+a[d[i-1]][d[i]]*K[i]*K[i-1]+a[d[i-1]][c[i]]*(1-K[i])*K[i-1]+a[c[i-1]][d[i]]*(1-K[i-1])*K[i]+a[c[i-1]][c[i]]*(1-K[i])*(1-K[i-1]));
            }
        }
    
    
        double ans=INF;
        for(int j=0;j<=m;++j) {
            ans=min(ans,f[n][j][0]);
            ans=min(ans,f[n][j][1]);
        }
        printf("%.2f",ans );
        return 0;
    }
    

    Day2T1

    思路:

    对于上面和下面的式子进行分解质因数,然后看看上面的质因数个数减去下面的质因数个数能不能达到k的质因数的要求即可。

    分解质因数的时候用对于阶乘分解质因数的常用方法:比如要求1999!中能分解出多少个5,那么就把1999不断的除以5,并且把得到的数相加即可。原因显然。

    但是上面方法的复杂度是nnt,明显tle,考虑优化。发现当k固定之后,对于每个n和m是固定的,并且似乎是可以转移的。所以考虑预处理。

    用c[i][j]表示(C_i^j)是不是符合要求。用g[i][j]表示当m为j,n从j到max满足条件的数量。f[i][j]表示n为1到i,m为1到j时满足条件的数量。

    然后只要考虑出f[i][j]的转移即可,显然f[i][j]=f[i][j-1]+g[i][j]

    然后只要O(1)查询即可,懒得现将询问读入再预处理,所以前面的预处理全都是到2000的。

    虽然跑的很慢,但是能过啊!!

    Day2T2

    80分思路:

    一个比较明显的思路就是用优先队列模拟。每次取出队首也就是最长的那个蚯蚓,然后将它割开,重新放回队列,然后考虑其他蚯蚓增长的问题,如果挨个加上的话肯定t飞掉了,所以可以用一个变量now表示当前将每个蚯蚓都加上了st,每取出一只蚯蚓都将它的长度加上now即可,注意割开之后的蚯蚓不能加上这次增长的长度,要处理一下。然后就有80分了

    100分思路:

    可以发现,因为是先对最长的蚯蚓进行处理,并且割开的比例相同,所以先割开的蚯蚓割开后的占大比例的那一块肯定比后割开的要长,同理,占小比例的那块可能也比后割开的要长,这样就有了单调性,只要用三个队列,分别表示原来的蚯蚓,割开后占大比例的蚯蚓,和割开后占小比例的蚯蚓。每次操作的时候从这三个队列的队首中找出最大的那条蚯蚓进行与80分做法类似的操作即可,操作之后再分别放入第2,3个队列。(虽然是100分做法,但是一不小心就会写挂,所以还是写80分或者分段程序保险!!)

    80分代码:

    #include<queue>
    #include<cstdio>
    #include<iostream>
    #define p u/v
    using namespace std;
    typedef long long ll;
    priority_queue<ll>q;
    double sta;
    ll now,n,m,u,v,sum,T;
    int main() {
        cin>>n>>m>>sum>>u>>v>>T;
        for(int i=1;i<=n;++i) {
            int x;
            cin>>x;
            q.push(x);
        }
        for(int i=1;i<=m;++i) {
            ll k=q.top()+now;
            q.pop();
            if(i%T==0) {
                printf("%lld ",k);
            }
            ll z=k*p;
            q.push(z-now-sum);
            q.push(k-z-now-sum);
            now+=sum;
        }
        printf("
    ");
        int js=0;
        while(!q.empty()) {
            js++;
            if(js%T==0) printf("%lld ",q.top()+now);
            q.pop();
        }
        return 0;
    }
    

    100分代码:

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<queue>
    #include<algorithm>
    using namespace std;
    #define p u/v
    typedef long long ll;
    queue<ll>q[4];
    ll read() {
        ll x=0;ll f=1;char c=getchar();
        while(!isdigit(c)) {
            if(c=='-') f=-1;
            c=getchar();
        }
        while(isdigit(c)) {
            x=x*10+c-'0';
            c=getchar();
        }
        return x*f;
    }
    bool cmp(int x,int y) {
        return x>y;
    }
    ll a[7100000+100],now,sum;
    int main() {
        ll n=read(),m=read(),sum=read(),u=read(),v=read(),t=read();
        //cout<<p<<endl;
        q[0].push(-0x7fffffff);
        for(int i=1;i<=n;++i)
            a[i]=read();
        sort(a+1,a+n+1,cmp);
        for(int i=1;i<=n;++i) 
            q[1].push(a[i]);
        /*for(int i=1;i<=n;++i) 
            cout<<a[i]<<" ";
        while(!q[1].empty()) {
            cout<<q[1].front()<<" ";
            q[1].pop();
        }*/
        for(int i=1;i<=m;++i) {
            int k=0;
            for(int j=1;j<=3;++j)
                if(!q[j].empty()&&q[j].front()>q[k].front()) k=j;
            ll z=q[k].front();
            q[k].pop();
            z+=now;
            if(i%t==0) printf("%lld ",z);
            ll zz=z*p;
            //cout<<z<<" "<<zz<<endl;
            q[2].push(zz-now-sum);
            q[3].push(z-zz-now-sum);
            now+=sum;
        }
        printf("
    ");
        for(int i=1;i<=n+m;++i) {
            int k=0;
            for(int j=1;j<=3;++j)
                if(!q[j].empty()&&q[j].front()>q[k].front()) k=j;
            if(i%t==0)	printf("%lld ",q[k].front()+now);
            q[k].pop();
        }
        return 0;
    }
    

    Day2T3

    思路:

    搜索+最优化剪枝

    (不多bb是因为抄的题解啊啊啊啊)

    代码:

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    using namespace std;
    const double eps=1e-8;
    bool dy(double a,double b) {
        return fabs(a-b)<eps;
    }
    int n,m,ans;
    double x[20],y[20],pwxa[20],pwxb[20],tx[20],ty[20];
    void dfs(int c,int u,int v) {
        if(u+v>=ans) return;
        if(c>n) {
            ans=u+v;
            return;
        }
        bool flag=0;
        for(int i=1;i<=u;++i) {
            if(dy(pwxa[i]*x[c]*x[c]+pwxb[i]*x[c],y[c])) {
                dfs(c+1,u,v);
                flag=1;
                break;
            }
        }
        if(!flag) {
            for(int i=1;i<=v;++i) {
                if(dy(x[c],tx[i])) continue;
                double a=(y[c]*tx[i]-ty[i]*x[c])/(x[c]*x[c]*tx[i]-tx[i]*tx[i]*x[c]);
                double b=(y[c]-x[c]*x[c]*a)/x[c];
                if(a<0) {
                    pwxa[u+1]=a;
                    pwxb[u+1]=b;
                    double q=tx[i],w=ty[i];
                    for(int j=i;j<v;++j) {
                        tx[j]=tx[j+1];
                        ty[j]=ty[j+1];
                    }
                    dfs(c+1,u+1,v-1);
                    for(int j=v;j>i;--j) {
                        tx[j]=tx[j-1];
                        ty[j]=ty[j-1];
                    }
                    tx[i]=q;
                    ty[i]=w;
                }
            }
            tx[v+1]=x[c];
            ty[v+1]=y[c];
            dfs(c+1,u,v+1);
        }
    }
    int main() {
        int T;
        scanf("%d",&T);
        while(T--) {
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;++i) scanf("%lf%lf",&x[i],&y[i]);
            ans=100;
            dfs(1,0,0);
            printf("%d
    ",ans);
        }
    
        return 0;
    }
    

    总结

    难度就不说了,为啥没有天天爱跑步,不会。。。。但是打满暴力就可以拿一等奖。虽然天天爱跑步的恶心程度难以想象,但是部分分还是可以拿的,即便很不幸,天天爱跑步只拿10分,又很不幸期望dp写挂了只拿5分,day1还可以有100+10+5=115。又很不幸组合数只拿了质数的那40分,又又很不幸蚯蚓只会那80分的优先队列,又又又很不幸愤怒的小鸟一分也没有,day2也有40+80+0=120分了,总共就有了235分了,这刚好是山东分数线啊。而且这么不幸的话可以去跳楼了

  • 相关阅读:
    python模块--time模块
    python模块--如何相互调用自己写的模块
    Animating Views Using Scenes and Transitions
    fragment 切换
    android textview 设置text 字体
    android intent 5.1
    android EditView ime
    animation of android (4)
    animation of android (3)
    animation of android (2)
  • 原文地址:https://www.cnblogs.com/wxyww/p/9609758.html
Copyright © 2011-2022 走看看