• 11.13 noip模拟试题


    题目名称 笔记 括号 城堡
    可执行文件名 note brackets castle
    输入文件名 note.in brackets.in castle.in
    输出文件名 note.in brackets.out castle.in
    每个测试点时限 1 秒 1 秒 1 秒
    内存限制 512MB 512MB 512MB
    测试点数目 20 20 10
    每个测试点分值 5 5 10
    是否有部分分 否 否 否
    题目类型 传统型 传统型 传统型
    测试题 #4 笔记
    笔记
    【问题描述】
    给定一个长度为?的序列?,下标编号为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。
    测试题 #4 笔记
    【数据规模和约定】
    31。
    60%的数据,?,? ≤ 2000。
    对于100%的数据,1 ≤ ?,? ≤ 100,000。

    /*暴力+小小的优化(没有啥大用)*/
    #include<cstdio>
    #include<ctime>
    #include<algorithm>
    #define maxn 100010
    using namespace std;
    int n,m,a[maxn],b[maxn],c[maxn],ans;
    int init(){
        int x=0,f=1;char s=getchar();
        while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
        while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
        return x*f;
    }
    int Abs(int x){
        return x<0?-x:x;
    }
    int main()
    {
        freopen("note.in","r",stdin);
        freopen("note.out","w",stdout);
        n=init();m=init();
        for(int i=1;i<=m;i++)
            a[i]=init();
        if(n<=100){
            for(int i=2;i<m;i++)
            if((a[i]<a[i-1]&&a[i]<a[i+1])||(a[i]>a[i-1]&&a[i]>a[i+1]))
                c[++c[0]]=a[i];
            c[++c[0]]=a[1];c[++c[0]]=a[m];
        }
        else for(int i=1;i<=n;i++)c[++c[0]]=a[i];
        sort(c+1,c+1+c[0]);
        c[0]=unique(c+1,c+1+c[0])-c-1;
        for(int i=1;i<m;i++)
            ans=ans+Abs(a[i+1]-a[i]);
        for(int i=1;i<=c[0];i++)
            for(int j=1;j<=n;j++){
                for(int k=1;k<=m;k++)
                    if(a[k]==c[i])b[k]=j;
                    else b[k]=a[k];
                long long mx=0;
                for(int k=1;k<m;k++){
                    mx=mx+Abs(b[k+1]-b[k]);
                    if(ans<mx)break;
                }
                if(ans>mx)ans=mx;
                //if(clock()>950){
                //    printf("%lld
    ",ans);return 0;
                //}
            }
        printf("%lld
    ",ans);
        fclose(stdin);fclose(stdout);
        return 0;
    }
    View Code
    /*
    嗯很好的思路 每个数字只与两边的有关
    假设我们尝试着改 x 改成什么玩意是可以直接算出来的
    先预处理处所有与x相邻的数们 那每个都要与x做差然后绝对值
    如果我们队这一坨数排序的话 那么显然x改成中位数最优
    然后枚举一下x 比较一下就好了
    每个x都要sort一遍 这个并不会很慢 均摊还是很快的 
    */
    #include<cstdio>
    #include<vector>
    #include<algorithm>
    #define maxn 100010
    #define ll long long
    using namespace std;
    ll n,m,a[maxn],b[maxn];
    ll sta,mx;
    vector<ll>G[maxn];
    ll init(){
        ll x=0,f=1;char s=getchar();
        while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
        while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
        return x*f;
    }
    ll Abs(ll x){
        return x<0?-x:x;
    }
    int main(){
        freopen("note.in","r",stdin);
        freopen("note.out","w",stdout);
        n=init();m=init();
        for(ll i=1;i<=m;i++)a[i]=init();
        for(ll i=1;i<=m;i++)
            if(a[i]!=a[i-1])b[++b[0]]=a[i];
        for(ll i=1;i<m;i++)sta+=Abs(a[i+1]-a[i]);
        m=b[0];b[0]=0;
        for(ll i=2;i<m;i++){
            G[b[i]].push_back(b[i-1]);
            G[b[i]].push_back(b[i+1]);
        }
        if(b[2])G[b[1]].push_back(b[2]);
        if(b[m-1])G[b[m]].push_back(b[m-1]);
        for(ll i=1;i<=n;i++){
            ll len=G[i].size();
            if(!len)continue;
            sort(G[i].begin(),G[i].end());
            ll mid=G[i][(len+1)/2-1];
            ll pre=0,now=0;
            for(ll k=0;k<len;k++){
                pre+=Abs(G[i][k]-i);
                now+=Abs(G[i][k]-mid);
            }
            mx=max(mx,pre-now);
        }
        printf("%I64d
    ",sta-mx);
        return 0;
    }
    View Code

    测试题 #4 括号
    括号
    【问题描述】
    有一个长度为?的括号序列,以及?种不同的括号。序列的每个位置上是哪
    种括号是随机的,并且已知每个位置上出现每种左右括号的概率。求整个序列是
    一个合法的括号序列的概率。
    我们如下定义合法括号序列:
     空序列是合法括号序列;
     如果?是合法括号序列,那么???是合法括号序列,当且仅当?和?是同种
    的左右括号;
     如果?和?是合法括号序列,那么??是合法括号序列。
    【输入格式】
    输入第一行包含两个整数?和?。接下来的输入分为?组,每组?行。第?组第
    ?行包含两个实数?[?,?]和?[?,?],分别代表第?个位置上是第?类的左括号和右括号
    的概率。
    【输出格式】
    输出一行,包含一个实数,代表序列是合法括号序列的概率。建议保留至少
    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 括号
    【样例输出 2】
    0.25000
    【数据规模和约定】
    对于20%的数据,? ≤ 50,? = 1,所有位置的概率非 0 即 1。
    另外有 30%的数据,? ≤ 34,? = 1,前 10 个和后 10 个位置的所有概率都
    是 0.5,中间剩余位置的概率非 0 即 1。
    80%的数据,?,? ≤ 50。
    对于100%的数据,1 ≤ ? ≤ 200,1 ≤ ? ≤ 50。

    /*dpwa成了傻逼 还是交的暴力*/
    #include<iostream>
    #include<cstdio>
    #define maxn 210
    #define ld long double
    using namespace std;
    int n,k,s[maxn];
    ld g[maxn][maxn][2],ans;
    void Dfs(int now,ld x){
        if(now==n+1){
            int falg=1;
            for(int i=1;i<=k;i++)
                if(s[i]){
                    falg=0;break;
                }
            if(falg)ans+=x;return;
        }
        for(int i=1;i<=k;i++){
            if(s[i]-1>=0&&g[now][i][1]){
                s[i]--;Dfs(now+1,x*g[now][i][1]);s[i]++;
            }
            if(s[i]+1<=n-now&&g[now][i][0]){
                s[i]++;Dfs(now+1,x*g[now][i][0]);s[i]--;
            }
                
        }
    }
    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>>g[i][j][0]>>g[i][j][1];
        if(n&1){
            printf("0.00000
    ");return 0;
        }
        Dfs(1,1);printf("%.5lf",double(ans));
        fclose(stdin);fclose(stdout);
        return 0;
    }
    View Code
    /*维护两个数组 很好的解决了重复计算的问题*/
    #include<iostream>
    #include<cstdio>
    #define ld long double
    #define maxn 210
    using namespace std;
    int n,k;
    ld f[maxn][maxn],ff[maxn][maxn],g[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>>g[i][j][0]>>g[i][j][1];
        for(int i=1;i<n;i++)
            for(int x=1;x<=k;x++)
                f[i][i+1]+=g[i][x][0]*g[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]+ff[i+1][j-1])*g[i][x][0]*g[j][x][1];
                for(int x=i+1;x<j-1;x++)
                    ff[i][j]+=(f[i][x]+ff[i][x])*f[x+1][j];
            }
        printf("%.5f
    ",(double)(f[1][n]+ff[1][n]));
        return 0;
    }
    View Code

    测试题 #4 城堡
    城堡
    【问题描述】
    给定一张?个点?条边的无向连通图,每条边有边权。我们需要从?条边中
    选出? − 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≤ ? ≤ 1000,? − 1 ≤ ? ≤
    ? ?−1
    2
    ,1 ≤ ? ≤ 100。

    /*暴力 dfs+SPFA+Tarjan+dfs*/
    #include<cstdio>
    #include<queue>
    #include<iostream>
    #include<cstring>
    #define maxn 1010
    using namespace std;
    int n,m,num,head[maxn],f[maxn],D[maxn],S[maxn],topt,top;
    int s[maxn],vis[maxn],dfn[maxn],low[maxn],sum,Sum[maxn];
    long long ans; 
    struct node{
        int u,v,t;
    }p[maxn];
    struct edge{
        int v,t,pre,x;
    }e[maxn*2];
    queue<int>q;
    int init(){
        int x=0,f=1;char s=getchar();
        while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
        while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
        return x*f;
    }
    void Add(int from,int to,int dis,int i){
        num++;e[num].v=to;
        e[num].x=i;
        e[num].t=dis;
        e[num].pre=head[from];
        head[from]=num;
    }
    void Tarjan(int x,int fa){
        dfn[x]=low[x]=++topt;
        s[++top]=x;vis[x]=1;
        for(int i=head[x];i;i=e[i].pre){
            int v=e[i].v;
            if(v==fa||!f[e[i].x])continue;
            if(dfn[v]==0){
                Tarjan(v,x);low[x]=min(low[x],low[v]);
            }
            else if(vis[v])low[x]=min(low[x],dfn[v]);
        }
        if(low[x]==dfn[x]){
            sum++;while(x!=s[top]){
                Sum[sum]++;vis[s[top]]=0;top--;
            }
            Sum[sum]++;vis[s[top]]=0;top--;
        }
    }
    bool Judge(){
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(s,0,sizeof(s));
        memset(vis,0,sizeof(vis));
        memset(Sum,0,sizeof(Sum));
        topt=top=sum=0;
        for(int i=1;i<=n;i++)
            if(dfn[i]==0)Tarjan(i,0);
        for(int i=1;i<=sum;i++)
            if(Sum[i]>1)return 0;
        return 1;
    }
    void SPFA(){
        memset(D,127/3,sizeof(D));
        D[1]=0;f[1]=1;q.push(1);
        while(!q.empty()){
            int k=q.front();q.pop();f[k]=0;
            for(int i=head[k];i;i=e[i].pre){
                int v=e[i].v;
                if(D[v]>D[k]+e[i].t){
                    D[v]=D[k]+e[i].t;
                    if(f[v]==0){
                        f[v]=1;q.push(v);
                    }
                }
            }
        }
    }
    void dfs(int now,int from,int x){
        S[now]=min(S[now],x);
        for(int i=head[now];i;i=e[i].pre){
            if(!f[e[i].x])continue;
            int v=e[i].v;if(v==from)continue;
            dfs(v,now,x+e[i].t);
        }
    }
    void Solve(){
        memset(S,127/3,sizeof(S));
        S[1]=0;dfs(1,1,0);
        for(int i=1;i<=n;i++)
            if(S[i]!=D[i])return;
        ans++;return;
    }
    void Dfs(int now){
        if(now==m+1){
            int cnt=0;
            for(int i=1;i<=m;i++)
                if(f[i])cnt++;
            if(cnt!=n-1||!Judge())return;
            Solve();return;
        }
        f[now]=1;Dfs(now+1);
        f[now]=0;Dfs(now+1);
    }
    int main()
    {
        freopen("castle.in","r",stdin);
        freopen("castle.out","w",stdout);
        n=init();m=init();
        int u,v,t;
        for(int i=1;i<=m;i++){
            u=init();v=init();t=init();
            p[i].u=u;p[i].v=v;p[i].t=t;
            Add(u,v,t,i);Add(v,u,t,i);
        }
        SPFA();memset(f,0,sizeof(f));Dfs(1);
        cout<<ans<<endl;
        fclose(stdin);fclose(stdout);
        return 0;
    }
    View Code
    /*
    很机智的题解
    维护每个点连出去的边中 有几个是最短路上的
    假设 两个点 ij i有a条连边是最短路上的 j有b条
    那么 1 i j 这三个点构成一棵树就有 1*a*b中方法
    加上其他的点同理
    最后乘法原理算一下 
    */
    #include<cstdio>
    #include<queue>
    #include<iostream>
    #include<cstring>
    #define ll long long
    #define mod ((1<<31)-1)
    #define maxn 1010
    using namespace std;
    int n,m,num,head[maxn],f[maxn],D[maxn],c[maxn];
    ll ans=1;
    struct node{
        int u,v,t;
    }p[maxn*maxn];
    struct edge{
        int v,t,pre;
    }e[maxn*2*maxn];
    queue<int>q;
    int init(){
        int x=0,f=1;char s=getchar();
        while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
        while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
        return x*f;
    }
    void Add(int from,int to,int dis){
        num++;e[num].v=to;
        e[num].t=dis;
        e[num].pre=head[from];
        head[from]=num;
    }
    void SPFA(){
        memset(D,127/3,sizeof(D));
        D[1]=0;f[1]=1;q.push(1);
        while(!q.empty()){
            int k=q.front();q.pop();f[k]=0;
            for(int i=head[k];i;i=e[i].pre){
                int v=e[i].v;
                if(D[v]>D[k]+e[i].t){
                    D[v]=D[k]+e[i].t;
                    if(f[v]==0){
                        f[v]=1;q.push(v);
                    }
                }
            }
        }
    }
    int main()
    {
        freopen("castle.in","r",stdin);
        freopen("castle.out","w",stdout);
        n=init();m=init();
        int u,v,t;
        for(int i=1;i<=m;i++){
            u=init();v=init();t=init();
            p[i].u=u;p[i].v=v;p[i].t=t;
            Add(u,v,t);Add(v,u,t);
        }
        SPFA();
        for(int i=1;i<=m;i++){
            if(D[p[i].v]==D[p[i].u]+p[i].t)c[p[i].v]++;
            if(D[p[i].u]==D[p[i].v]+p[i].t)c[p[i].u]++;
        }
        for(int i=2;i<=n;i++)
            ans=ans*(ll)c[i]%mod;
        cout<<ans<<endl;
        fclose(stdin);fclose(stdout);
        return 0;
    }
    View Code
  • 相关阅读:
    “三路九招”打赢电商低成本营销战
    我的文章分类
    ResourceBundle读取中文properties文件问题
    敏捷基础知识
    一个简单方法:构造xml的document,并将其转换为string
    在android源码环境下写上层应用的一个初步解决方法
    Linux 与 unix shell编程指南——学习笔记
    git 分支的基本操作
    使用repo的本地开发流程
    Linux常用命令收集
  • 原文地址:https://www.cnblogs.com/yanlifneg/p/6059343.html
Copyright © 2020-2023  润新知