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
原文地址:https://www.cnblogs.com/yanlifneg/p/6059343.html