首页 > 代码库 > 11.13 noip模拟试题

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 100010using 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\n",ans);return 0;            //}        }    printf("%lld\n",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 longusing 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\n",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 doubleusing 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\n");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 210using 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\n",(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 1010using 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 1010using 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

11.13 noip模拟试题