• 2017.3.25NOIP模拟测试


    1. 简单的数列
    【问题描述】
    一个简单的数列问题:
    给定一个长度为 n 的数列,求数列中这样的三个元素 ai,aj,ak 的个数,满足 ai< aj > ak,
    且 i<j<k 。
    【输入】
    第 1 行是一个整数 n(1<=n<=50000)

    接下来 n 行,每行一个元素 ai(0 <= ai <= 32767)。
    【输出】
    一个数,满足 ai<aj>ak (i<j<k) 的个数。
    【输入输出样例】
    Input
    5
    1
    2
    3
    4
    1
    Output
    6
    【数据范围】
    对于 30%的输入数据有 n<=2000。
    对于 80%的输入数据有 n<=10000。
    对于 100%的输入数据有 n<=50000。

    第一题,树状数组板子题

     1 #define ll long long
     2 #include<algorithm>
     3 #include<iostream>
     4 #include<iomanip>
     5 #include<cstring>
     6 #include<cstdlib>
     7 #include<cstdio>
     8 #include<queue>
     9 #include<ctime>
    10 #include<cmath>
    11 #include<stack>
    12 #include<map>
    13 #include<set>
    14 
    15 using namespace std;
    16 const int maxn=50010;
    17 int C1[maxn],C2[maxn];
    18 int a[maxn],b[maxn];
    19 int c1[maxn],c2[maxn];
    20 int n;
    21 void add1(int p,int x) {
    22     while(p<=32768) {
    23         C1[p]++;
    24         p+= (p & (-p));
    25     }
    26 }
    27 void add2(int p,int x) {
    28     while(p<=32768) {
    29         C2[p]++;
    30         p+=(p & (-p));
    31     }
    32 }
    33 int getsum1(int p) {
    34     int sum=0;
    35     while(p) {
    36         sum+=C1[p];
    37         p-=(p & (-p));
    38     }
    39     return sum;
    40 }
    41 int getsum2(int p) {
    42     int sum=0;
    43     while(p) {
    44         sum += C2[p];
    45         p-=(p & (-p));
    46     }
    47     return sum;
    48 }
    49 int main() {
    50     freopen("queueb.in","r",stdin);
    51      freopen("queueb.out","w",stdout);
    52     cin>>n;
    53     int i;
    54     for(i=1; i<=n; i++) scanf("%d",&a[i]),a[i]++;
    55     for(i=1; i<=n; i++) b[i]=a[n-i+1];
    56     for(i=1; i<=n; i++) {
    57         add1(a[i],1);
    58         int p=a[i]-1;
    59         if(!p) continue;
    60         c1[i]=getsum1(p);
    61     }
    62     for(i=1; i<=n; i++) {
    63         add2(b[i],1);
    64         int p=b[i]-1;
    65         if(!p) continue;
    66         c2[i]=getsum2(p);
    67     }
    68     int ll sum=0;
    69     for(i=1; i<=n; i++) {
    70         sum += (ll) c1[i] * (ll) c2[n-i+1];
    71     }
    72     cout<<sum;
    73     return 0;
    74 }
    View Code


    - 2 -2. 黄金矿工
    【问题描述】
    黄金矿工是一个经典的小游戏,它可以锻炼人的反应能力。该游戏中,可以通过“挖矿”
    获得积分并不断升级。玩家可以在线玩 flash 版黄金矿工,也可以下载后玩单机版黄金矿工。
    目前,黄金矿工小游戏有多个版本,例如黄金矿工双人版,黄金矿工单人版等。
    Jimmy 是一位黄金矿工,他所在的金矿是一个 n*n 的矩形区域(俯视),区域内有黄金、
    石头和 TNT,由一个 n*n 的矩阵描述。黄金的价值对应矩阵中的正值,石头的价值对应矩阵
    中的负值,TNT 由 0 表示。换句话说,挖到黄金赚钱,石头亏损,如果挖到 TNT 就挂了。
    Jimmy 租到的挖矿工具很特别,它的形状是一个长宽任意(均为正整数)的矩形,可以
    取走被该工具覆盖的矩形区域内的所有物品,但如果该区域内有 TNT,该工具将被炸毁,此
    时 Jimmy 将不得不赔偿矿主+∞元!!
    !需要注意的是,该工具只能在金矿范围内使用(即不
    得超出金矿边界),且租金为每次使用十元。
    现在,Jimmy 想知道,如果他至多只有一次租用该工具的机会,他能获得的最大收益是
    多少。当然,如果 Jimmy 租用该工具无论如何都会亏损,他可以不租用,此时收益为 0.
    【输入】
    第一行:一个整数 n
    接下来 n 行,每行 n 个整数(绝对值<100)
    ,为题目中所描述的矩阵。
    【输出】
    一个数,即 Jimmy 所能获得的最大收益。
    【输入输出样例 1】
    Input
    3
    0 -1 -1
    0 -12 0
    -19 0 0
    Output
    0
    【样例解释】
    无论 Jimmy 怎么挖矿,挖到的不是石头,就是 TNT,总之无论如何都会亏损,所以选择不租
    用工具,收益为 0
    【数据范围】
    对于 30%的数据:0<n<=10
    对于 60%的数据:0<n<=100
    对于 100%的数据:0<n<=300

    第二题,考场上没能写出来,。。。其实这个题要用到决策性优化,如果只有一列,则最大的值这样表示,f[i]表示以i结尾的 值最大的长条,设s[i]为前缀和,则f[i]=max(s[i]-s[k])(k<i),即找到一个最小的k,这是一个决策。那么对于i来说,i 的前面最小的也是在k的时候取得最小,是一样的,所以i的决策就是i-1的决策,如果s[i] < s[k],则把k置为i。回到这题,只是把一维变成了二维,使用二位前缀和,相当于还是一样的,只要枚举一下长度,矩阵的坐标,O(n^3);

     1 #define ll long long
     2 #include<algorithm>
     3 #include<iostream>
     4 #include<iomanip>
     5 #include<cstring>
     6 #include<cstdlib>
     7 #include<cstdio>
     8 #include<queue>
     9 #include<ctime>
    10 #include<cmath>
    11 #include<stack>
    12 #include<map>
    13 #include<set>
    14 #define SS system("pause");
    15 #define inf 3000000
    16 using namespace std;
    17 const int N=310;
    18 int a[N][N],h[N][N];
    19 int n,ans=0;
    20 void go_30() {
    21     int i,j,k; 
    22     for(int len=1;len<=n;len++) {
    23     for(i=n;i>=len;i--){
    24         k=0;
    25         for(j=1;j<=n;j++){
    26         int op=h[i][k]-h[i-len][k];
    27         int now=h[i][j]-h[i-len][j];
    28         if(now<op) k=j; 
    29         else ans=max(ans,now-op);
    30         }
    31     }
    32     }
    33 }
    34 int main() {
    35     freopen("miner.in","r",stdin);
    36              freopen("miner.out","w",stdout);
    37     cin>>n;int i,j;
    38     for(i=1;i<=n;i++)
    39       for(j=1;j<=n;j++) {
    40         scanf("%d",&a[i][j]);
    41         if(!a[i][j]) a[i][j]=-inf;
    42         h[i][j] = h[i][j-1]+a[i][j];
    43       }
    44     for(i=2;i<=n;i++) 
    45       for(j=1;j<=n;j++)
    46         h[i][j] += h[i-1][j];
    47     go_30(); 
    48     if(ans<=10) cout<<0;
    49     else cout<<ans-10;
    50     return 0;
    51 }
    View Code


    - 3 -3. 旅行
    【问题描述】
    Z 小镇是一个景色宜人的地方,吸引来自各地观光客来此旅游观光。Z 小镇附近共有 N
    个景点(编号为 1,2,3...N)
    ,这些景点被 M 条道路连接着,所有道路都是双向的,两个
    景点之间可能有多条道路连接着。
    也许是为了保护该地的旅游资源,Z 小镇有个奇怪的规定,就是对于一条给定的公路
    Ri,任何在该公路上行驶的车辆速度必须为 Vi。速度变化太快使得游客们很不舒服,因此
    从一个景点前往另一个景点的时候,大家都希望选择行使过程中最大速度和最小速度的比尽
    可能小的路线,也就是所谓最舒适路线。
    【输入】
    第一行包括两个整数: N 和 M
    接下来的 M 行每行包含三个正整数: x,y 和 v。表示景点 x 到景点 y 之间有一条双向
    公路,车辆必须以速度 v 在该公路上行驶。
    最后一行包含两个正整数 s,t,
    表示想知道从景点 s 到景点 t 最大最小速度比最小的路径。
    s 和 t 不可能相同。
    【输出】
    如果景点 s 到景点 t 没有路径,输出“IMPOSSIBLE”
    。否则输出一个数,表示最小的速
    度比。如果需要,输出一个既约分数。
    【输入输出样例 1】
    Input
    4
    1
    3
    1
    2
    2 1
    4 2
    4
    【输入输出样例 2】
    Input
    3
    1
    1
    2
    1
    3
    2 10
    2 5
    3 8
    3
    【输入输出样例 3】
    Input
    3
    1
    2
    1
    2
    2 2
    3 4
    3
    Output
    IMPOSSIBLE
    Output
    5/4
    Output
    2

    因为只要的到最大值与最小值的比值,能有一条路径连通s,t即可,如果确定了最小值,只需要找到最小的最大值的边使得s,t连通,于是把边从小到大排序,从一到n枚举每一条边,设置他为最小边,在他后面按顺序加边,直到s与t连通,得到一个比值,不断更新答案即可;连通只要用并查集就行。

     1 #include<algorithm>
     2 #include<iostream>
     3 #include<iomanip>
     4 #include<cstring>
     5 #include<cstdlib>
     6 #include<cstdio>
     7 #include<queue>
     8 #include<ctime>
     9 #include<cmath>
    10 #include<stack>
    11 #include<map>
    12 #include<set>
    13 #define inf 199999999
    14 #define db double
    15 using namespace std;
    16 const int N=510,M=5010;
    17 struct E{
    18     int to,net,w;
    19     int fr;
    20 }e[M*2];
    21 int n,m,num_e,head[N],s,t;
    22 int fa[N];
    23 void add(int x,int y,int w) {
    24     e[++num_e].to=y;e[num_e].net=head[x];e[num_e].w=w;head[x]=num_e;e[num_e].fr=x;
    25 }
    26 int gcd(int a,int b) {
    27     return a%b==0? b :gcd(b,a%b);
    28 }
    29 int comp(const E &a,const E &b ){
    30     return a.w<b.w;
    31 }
    32 void init() {
    33     for(int i=1;i<=n;i++) fa[i]=i;
    34 }
    35 int find(int x) {
    36     if(x!=fa[x]) fa[x]=find(fa[x]);
    37     return fa[x];
    38 }
    39 void Union(int x,int y) {
    40     fa[y]=x;
    41 }
    42 int main() {
    43     freopen("comf.in","r",stdin);
    44     freopen("comf.out","w",stdout);
    45     memset(head,-1,sizeof(head));
    46     cin>>n>>m;int i;
    47     int a,b;
    48     a=inf;b=1;
    49     for(i=1;i<=m;i++) {
    50         int x,y,w;scanf("%d%d%d",&x,&y,&w);
    51         add(x,y,w);
    52     }
    53     cin>>s>>t;
    54     sort(e+1,e+m+1,comp);
    55     for(i=1;i<=m;i++) {
    56         init();int j;
    57         int minn=e[i].w;
    58         for(j=i;j<=m;j++){
    59         int r1=find(e[j].fr),r2=find(e[j].to);
    60         if(r1!=r2) {
    61             Union(r1,r2);
    62           
    63         }
    64         //        printf("%d %d
    ",r1,r2);
    65         if(find(s)==find(t)) break;
    66         }
    67         if(j>m) break;
    68         if((db)e[j].w/(db)minn<(db)a/(db)b) a=e[j].w,b=minn;
    69     }
    70     int c=gcd(a,b);
    71     a/=c,b/=c;
    72     if(a==inf) {
    73         puts("IMPOSSIBLE");return 0;
    74     } 
    75     if(b==1) printf("%d",a);
    76     else printf("%d/%d",a,b);
    77     return 0;
    78 }
    View Code


    【数据范围】
    0<N<=500;0<M<=5000;
    - 4 -4. 奶牛跑步
    【问题描述】
    Bessie 准备用从牛棚跑到池塘的方法来锻炼. 但是因为她懒,她只准备沿着下坡的路跑
    到池塘,然后走回牛棚.
    Bessie 也不想跑得太远,所以她想走最短的路经. 农场上一共有 M(1<=M<=10,000)条路,
    每条路连接两个用 1..N(1<=N<=1000)标号的地点. 更方便的是,如果 X>Y,则地点 X 的高度大
    于地点 Y 的高度. 地点 N 是 Bessie 的牛棚;地点 1 是池塘.
    很快, Bessie 厌倦了一直走同一条路.所以她想走不同的路,更明确地讲,她想找出
    K(1<=K<=100)条不同的路经.为了避免过度劳累,她想使这 K 条路径为最短的 K 条路径.
    请帮助 Bessie 找出这 K 条最短路经的长度.你的程序需要读入农场的地图, 一些从 Xi
    到 Yi 的路径和它们的长度(Xi,Yi,Di).
    所有(Xi,Yi,Di) 满足( 1<=Yi<Xi; Yi<Xi<=N, 1<=Di<=1,000,000 ).
    【输入】
    第 1 行: 3 个数: N,M,K
    第 2..M+1 行: 第 i+1 行包含 3 个数 Xi,Yi,Di, 表示一条下坡的路.
    【输出】
    第 1..K 行: 第 i 行包含第 i 最短路径的长度,或−1 如果这样的路径不存在.如果多条路径
    有同样的长度,请注意将这些长度逐一列出.
    【输入输出样例】
    Input
    5
    5
    5
    5
    5
    4
    3
    3
    2
    8
    4
    3
    2
    1
    3
    1
    2
    1
    7
    1
    1
    1
    1
    4
    1
    1
    1
    Output
    1
    2
    2
    3
    6
    7
    -1
    【样例解释】
    路径分别为(5−1),(5−3−1),(5−2−1),(5−3−2−1),(5−4−3−1),(5−4−3−2−1)

    k短路,A*搜所,构造反图,处理处终点到每个点的最短距离,每次开启队列里dist+dis[u]最小的来扩展,一旦扩展到终点,就意味着找到了一条最短路,当第K次扩展到的时候就是第K短路。。。

     1 #define ll long long
     2 #include<algorithm>
     3 #include<iostream>
     4 #include<iomanip>
     5 #include<cstring>
     6 #include<cstdlib>
     7 #include<cstdio>
     8 #include<queue>
     9 #include<ctime>
    10 #include<cmath>
    11 #include<stack>
    12 #include<map>
    13 #include<set>
    14 using namespace std;
    15 const int N=1010,M=10010;
    16 struct E{
    17     int to,net,w;
    18 }e[M],e2[M];
    19 int n,m,k,num_e,num;
    20 int head[N],h[N];
    21 void add(int x,int y,int w) {
    22     e[++num_e].to=y;e[num_e].net=head[x];e[num_e].w=w;head[x]=num_e;
    23 }
    24 void add2(int x,int y,int w) {
    25     e2[++num].to=y;e2[num].w=w;e2[num].net=h[x];h[x]=num;
    26 }
    27 int dis[N],cnt[N];
    28 bool inq[N];
    29 void spfa(int s,int t) {
    30     queue<int> q;
    31     q.push(s);
    32     inq[s]=1;
    33     memset(dis,0x3f,sizeof(dis));
    34     dis[s]=0;
    35     while(!q.empty()) {
    36     int u=q.front();q.pop();
    37     inq[u]=0;//不加会萎
    38     for(int i=h[u];i;i=e2[i].net) {
    39         int to=e2[i].to;
    40         if(dis[to]>dis[u]+e2[i].w) {
    41         dis[to]=dis[u]+e2[i].w;
    42         if(!inq[to]) q.push(to),inq[to]=1;
    43         }
    44     }
    45     }
    46 }
    47 struct Node{
    48     int id,dist;
    49     bool operator<(const Node & b)const{
    50     return dist + dis[id] > b.dist +dis[b.id];
    51     }
    52 };//Yinpengzhe200104234532
    53 void a_star(int s,int t) {
    54     priority_queue<Node> q;
    55     Node tmp={s,0},tt;
    56     q.push(tmp);
    57     while(!q.empty()) {
    58     tmp=q.top();q.pop();
    59     cnt[tmp.id]++;
    60     if(tmp.id==t) {
    61         printf("%d
    ",tmp.dist);
    62         if(cnt[tmp.id]==k) return;
    63     }
    64     if(cnt[tmp.id]>k) continue;
    65     for(int i=head[tmp.id];i;i=e[i].net) {
    66         int to=e[i].to;
    67         tt=(Node){to,tmp.dist+e[i].w};
    68         q.push(tt);
    69     }
    70     }
    71 }
    72 int main() {
    73     freopen("cowjog.in","r",stdin);
    74     freopen("cowjog.out","w",stdout);
    75     cin>>n>>m>>k;int i;
    76     for(i=1;i<=m;i++) {
    77         int x,y,w;
    78         scanf("%d%d%d",&x,&y,&w);
    79         add(x,y,w);add2(y,x,w);
    80     }
    81     spfa(1,n);
    82     a_star(n,1);
    83     while(cnt[1]<k) puts("-1"),cnt[1]++;
    84     return 0;
    85 }
    View Code

    。。。。。。

    我想要的 我自然会认真.
  • 相关阅读:
    React.Fragment
    微信分享
    视频H5 video标签最佳实践
    详解vue2.0+vue-video-player实现hls播放全过程
    call()和appl()的理解
    JS 原生面经从初级到高级
    vue面试
    面试题2
    IdentityServer4 实现 OpenID Connect 和 OAuth 2.0
    DDD关键知识点整理汇总
  • 原文地址:https://www.cnblogs.com/ypz999/p/flow.html
Copyright © 2020-2023  润新知