zoukankan      html  css  js  c++  java
  • Qbxt AH d4 && day-6

    /*
    这两天考试直接呵呵了.
    赶脚对qbxt的题目无感.
    同时也发现了自己的一些问题.
    一些思路题总是自己傻逼的挖个坑跳进去.
    这两天场场倒数ORZ.
    始终是最弱的....
    然后NOIP光荣三等奖了吧%>_<%.
    */

    笔记
    【问题描述】
    给定一个长度为?的序列?,下标编号为1~?。序列的每个元素都是1~?的
    整数。定义序列的代价为
    ? ?+1 − ? ?
    ?−1
    ?=1
    你现在可以选择两个数?和?,并将序列?中所有的?改成?。?可以与?相等。
    请求出序列最小可能的代价。
    【输入格式】
    输入第一行包含两个整数?和?。第二行包含?个空格分隔的整数,代表序
    列?。
    【输出格式】
    输出一行,包含一个整数,代表序列最小的代价。
    【样例输入 1】
    4 6
    1 2 3 4 3 2
    【样例输出 1】
    3
    【样例输入 2】
    10 5
    9 4 3 8 8
    【样例输出 1】
    6
    【样例解释】
    样例 1 中,最优策略为将 4 改成 3。样例 2 中,最优策略为将 9 改成 4。
    【数据规模和约定】
    31。
    60%的数据,?,? ≤ 2000。
    对于100%的数据,1 ≤ ?,? ≤ 100,000。

    /*
    呵呵了.
    线性找的拐点然后乱搞.
    正确性显然不对.
    还骗了50分...... 
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #define MAXN 100001
    #define LL long long
    using namespace std;
    LL a[MAXN],s[MAXN],n,m,f[MAXN],tot,ans=1e18,total,c[MAXN];
    int read1()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
        return x*f;
    }
    int abs1(LL x)
    {
        return x<0?-x:x;
    }
    void slove()
    {
        bool flag=true;
        if(a[m]==a[1])
        {
            int x=a[1];
            for(int i=2;i<=m-1;i++)
              if(a[i]!=x) {flag=false;break;}
            if(flag) {
                printf("0");return ;
            }
        }
        memset(s,127/3,sizeof s);
        if(a[1]<a[2]) flag=true;
        else flag=false;
        f[a[1]]++;f[a[m]]++;
        for(int i=2;i<=m-1;i++)
        {
            if(a[i+1]>a[i]&&!flag)
              flag=true,f[a[i]]++;
            else if(a[i]>a[i+1]&flag)
              flag=false,f[a[i]]++;
            if(a[i]==a[i+1]) f[a[i]]++;
        }
        for(int i=2;i<=m-1;i++)
        {
            if(f[a[i]])
            {
                s[a[i]]=min(s[a[i]],max(a[i+1],a[i-1]));
                if(a[i]>a[i-1]&&a[i]<a[i+1])continue;
                if(a[i]<a[i-1]&&a[i+1]<a[i]) continue;
                c[a[i]]+=min(abs1(a[i-1]-a[i]),abs1(a[i+1]-a[i]))*2;
            }
        }
        if(s[a[1]]==s[0]) s[a[1]]=a[1];
        if(s[a[m]]==s[0]) s[a[m]]=a[m];
        if(s[a[1]]!=a[1])
        c[a[1]]+=abs1(a[1]-a[2])-abs1(s[a[1]]-a[2]);
        else c[a[1]]+=abs1(a[1]-a[2]);
        if(s[a[m]]!=a[m])
        c[a[m]]+=abs1(a[m]-a[m-1])-abs1(s[a[m]]-a[m-1]);
        for(int i=1;i<=n;i++)
          if(f[i]) ans=min(ans,total-c[i]);
        cout<<ans;
    }
    int main()
    {
        freopen("note.in","r",stdin);
        freopen("note.out","w",stdout);
        n=read1(),m=read1();
        if(m==1)
        {
            printf("0");return 0;
        }
        for(int i=1;i<=m;i++) a[i]=read1();
        for(int i=2;i<=m;i++)
          total+=abs1(a[i]-a[i-1]);
        slove();
        fclose(stdin);fclose(stdout);
        return 0;
    }
    /*
    思路题.
    找一个数找他的相邻数.
    (ans最大的这个数必定是拐点)
    (这告诉我们有时候就要用vector).
    然后找这些数的中位数
    (why?在一个单调区间中改一个数是毫无意义的
    然后我们可能会想到改成平均数but 若该平均数不在该区间中
    则改平均数一定不如中位数优.)
    */
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<vector>
    #define MAXN 100001
    #define LL long long 
    using namespace std;
    LL n,m,a[MAXN],ans,s;
    vector<int>b[MAXN];
    LL read()
    {
        LL x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
        return x*f;
    }
    LL abs1(LL x)
    {
        return x<0?-x:x;
    }
    int main()
    {
        int y,la;
        freopen("note.in","r",stdin);
        freopen("note.out","w",stdout);
        n=read(),m=read();
        for(int i=1;i<=m;i++) a[i]=read();
        for(int i=1;i<=m;i++)
        {
            if(i>1&&a[i-1]!=a[i])
              b[a[i-1]].push_back(a[i]);
            if(i<m&&a[i+1]!=a[i])
              b[a[i+1]].push_back(a[i]);
        }
        for(int i=1;i<=n;i++)
        {
            if(!b[i].size()) continue;
            sort(b[i].begin(),b[i].end());
            y=b[i][b[i].size()>>1];
            long long be=0,after=0;
            for(int j=0;j<b[i].size();j++)
            {
                la+=abs(i-b[i][j]);
                after+=abs(y-b[i][j]);
            }
            ans=max(ans,la-after);
            s+=la;
        }
        cout<<s/2-ans;
        fclose(stdin);
        fclose(stdout);
        return 0;
    }

    括号
    【问题描述】
    有一个长度为?的括号序列,以及?种不同的括号。序列的每个位置上是哪
    种括号是随机的,并且已知每个位置上出现每种左右括号的概率。求整个序列是
    一个合法的括号序列的概率。
    我们如下定义合法括号序列:
    • 空序列是合法括号序列;
    • 如果?是合法括号序列,那么???是合法括号序列,当且仅当?和?是同种
    的左右括号;
    • 如果?和?是合法括号序列,那么??是合法括号序列。
    【输入格式】
    输入第一行包含两个整数?和?。接下来的输入分为?组,每组?行。第?组第
    ?行包含两个实数?[?,?]和?[?,?],分别代表第?个位置上是第?类的左括号和右括号
    的概率。
    【输出格式】
    输出一行,包含一个实数,代表序列是合法括号序列的概率。建议保留至少
    5 位小数输出。只有当你的输出与标准答案之间的绝对误差不超过10 −5 时,才会
    被判为正确。
    【样例输入 1】
    2 1
    1.00000 0.00000
    0.00000 1.00000
    【样例输出 1】
    1.00000
    【样例输入 2】
    4 1
    0.50000 0.50000
    1.00000 0.00000
    0.00000 1.00000
    0.50000 0.50000
    测试题 #4 括号
    第 5 页 共 6 页
    【样例输出 2】
    0.25000
    【数据规模和约定】
    对于20%的数据,? ≤ 50,? = 1,所有位置的概率非 0 即 1。
    另外有 30%的数据,? ≤ 34,? = 1,前 10 个和后 10 个位置的所有概率都
    是 0.5,中间剩余位置的概率非 0 即 1。
    80%的数据,?,? ≤ 50。
    对于100%的数据,1 ≤ ? ≤ 200,1 ≤ ? ≤ 50。

    /*
    区间DP.
    f[i][j]表示[i,j]区间第一类合并对答案的贡献.
    g[i][j]表示[i,j]区间第二类合并对答案的贡献.
    一开始预处理单元区间f[i][i+1]+=s[i][x][0]*s[i+1][x][1].
    考虑两种区间合并. 
    第一类f[i][j]+=(f[i+1][j-1]+g[i+1][j-1])*s[i][x][0]*s[j][x][1].
    左右括号里边所有贡献*括号的贡献.
    第二类g[i][j]+=(f[i][x]+g[i][x])*f[x+1][j].
    为避免重复计算我们约定后边的始终为f. 
    */
    #include<iostream>
    #include<cstdio>
    #define ld long double
    #define MAXN 210
    using namespace std;
    int n,k;
    ld f[MAXN][MAXN],g[MAXN][MAXN],s[MAXN][MAXN][2];
    int main(){
        freopen("brackets.in", "r", stdin);
        freopen("brackets.out", "w", stdout);
        cin>>n>>k;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=k;j++)
                cin>>s[i][j][0]>>s[i][j][1];
        for(int i=1;i<n;i++)
            for(int x=1;x<=k;x++)
                f[i][i+1]+=s[i][x][0]*s[i+1][x][1];
        for(int i=n-1;i>=1;i--)
            for(int j=i+3;j<=n;j++){
                for(int x=1;x<=k;x++)
                    f[i][j]+=(f[i+1][j-1]+g[i+1][j-1])*s[i][x][0]*s[j][x][1];
                for(int x=i+1;x<j-1;x++)
                    g[i][j]+=(f[i][x]+g[i][x])*f[x+1][j];
            }
        printf("%.5f
    ",(double)(f[1][n]+g[1][n]));
        return 0;
    }

    城堡
    【问题描述】
    给定一张?个点?条边的无向连通图,每条边有边权。我们需要从?条边中
    选出? − 1条, 构成一棵树。 记原图中从 1 号点到每个节点的最短路径长度为? ? ,
    树中从 1 号点到每个节点的最短路径长度为? ? ,构出的树应当满足对于任意节点
    ?,都有? ? = ? ? 。
    请你求出选出? − 1条边的方案数。
    【输入格式】
    输入的第一行包含两个整数?和?。
    接下来?行,每行包含三个整数?、?和?,描述一条连接节点?和?且边权为
    ?的边。
    【输出格式】
    输出一行,包含一个整数,代表方案数对2 31 − 1取模得到的结果。
    【样例输入】
    3 3
    1 2 2
    1 3 1
    2 3 1
    【样例输出】
    2
    【数据规模和约定】
    32 ≤ ? ≤ 5,? ≤ 10。
    对于50%的数据,满足条件的方案数不超过 10000。
    对于100%的数据,2≤ N ≤ 1000,? − 1 ≤ M ≤
    N*(N-1)*2
    21 ≤ W ≤ 100。

    /*
    一开始
    tarjan+spfa+并查集+MST+dfs 150line乱搞.
    然后发觉自己读错题了.
    然后暴力没码完orz.
    这题要用到最短路性质.
    N的点 M条边(m>=n-1)的无向图
    跑最短路后最多还剩下N-1条边对答案有贡献.
    so spfa后枚举边乘法原理稍微搞搞就行了. 
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #define MAXN 1001
    #define MAXM 1000001
    #define LL long long
    const LL mod = (1LL << 31) - 1LL;
    using namespace std;
    int n,m,head[MAXN],tot,cut;
    LL ans=1;
    bool b[MAXN],vis[MAXM*2];
    struct edge{int u,v,next,x;}e[MAXM*2];
    struct data{LL ans,tot;}dis[MAXN];
    inline int read1()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
        return x*f;
    }
    inline void add(int u,int v,int x)
    {
        e[++cut].v=v;
        e[cut].u=u;
        e[cut].x=x;
        e[cut].next=head[u];
        head[u]=cut;
    }
    void spfa()
    {
        queue<int>q;
        for(int i=1;i<=n;i++) dis[i].ans=1e9;
        q.push(1);dis[1].ans=0;
        while(!q.empty())
        {
            int u=q.front();q.pop();b[u]=false;
            for(int i=head[u];i;i=e[i].next)
            {
                int v=e[i].v;
                if(dis[v].ans>dis[u].ans+e[i].x)
                {
                    dis[v].ans=dis[u].ans+e[i].x;
                    if(!b[v]) b[v]=true,q.push(v);
                }
            }
        }
        memset(b,0,sizeof b);
        for(int i=1;i<=n;i++)
        q.push(i);
        for(int i=1;i<=cut;i++)
        {
            int u=e[i].u,v=e[i].v;
            if(dis[v].ans==dis[u].ans+e[i].x) dis[v].tot++;
        }
        dis[1].tot=1;
        for(int i=1;i<=n;i++)
          ans=(ans*dis[i].tot)%mod;
        cout<<ans;
    }
    int main()
    {
        int x,y,z;
        freopen("castle.in","r",stdin);
        freopen("castle.out","w",stdout);
        n=read1(),m=read1();
        if(m==n-1){printf("1");return 0;}
        for(int i=1;i<=m;i++)
        {
            x=read1(),y=read1(),z=read1();
            add(x,y,z),add(y,x,z);
        }
        spfa();
        fclose(stdin);fclose(stdout);
        return 0;
    }
  • 相关阅读:
    iOS 图像渲染原理
    胶水语言
    关于事件处理
    redux有价值的文档
    redux沉思录
    详解JavaScript中的Object对象
    js 类型系统的核心:元类型、原型链与内省机制
    范畴、类型、复合、函数式编程
    js的类型系统--js基于原型的基石是所有对象最终都能够类型自证
    windows下查看dns缓存和刷新缓存
  • 原文地址:https://www.cnblogs.com/nancheng58/p/10068154.html
Copyright © 2011-2022 走看看