金山中学 rugular SRM 04 ——纪念我的第一次Ak

虽然只是一场比较简单的比赛 但奈何我也比较弱啊....

T1 一道计算概率的题目

T SRM 04

描述

给个长度为 n 的数列,每次操作能将数列打乱(RandomShuffle),问在期望下需要多少次操作才能得到一个不降数列。

输入格式

第一行一个整数 n 表示数列长度

第二行 n 个整数 A_{1..n} 表示数列

输出格式

一个小数表示期望操作次数,四舍五入至 6 位小数输出

样例输入

2
5 2

样例输出

2.000000

数据范围与约定

  • 1 leq n leq 18
  • 1 leq A_i leq 100

这道题想了一下 发现n很小那么n这么小,原因竟然是。。最小答案随n增大而超指数级衰减?

所以我写了个没有重复元素的全排列就是答案了 当然还得特殊考虑一开始就是符合要求而不需要打乱的情况 然后四舍五入

我是这么写的printf("%.6lf",ans+1e-10); 因为啊%.6f 是输出六位,四舍六入,为了四舍五入就+eps

贴一波代码 233

#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long 
using namespace std;
int read(){
    int ans=0,f=1,c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();}
    return ans*f; 
}
int n;
int w[1007],sum[1007];
double ans=1,mx;
bool f=1;
int main()
{
    n=read();
    for(double i=n;i;i=i-1) ans=ans*i; 
    for(int i=1;i<=n;i++){
        w[i]=read(); sum[w[i]]++;
        if(w[i]<w[i-1]) f=0;
    }
    if(f){printf("%.6lf
",1.0*0); return 0;}
    for(int i=1;i<=107;i++){
        if(sum[i]<=1) continue;
        mx=1;
        for(double k=1;k<=sum[i];k=k+1) mx=mx*k;
        ans=ans/mx;
    }
    printf("%.6lf",ans+1e-10);
    return 0;
}
View Code

T2 

J SRM 04

背景&&描述

    在一个似曾相识的春分的前一天,罚吹们组队参加了新岛老贼组织的ghost parade
    游行在一条大街上举行,出于反情侣的目的,新岛老贼做规划的时候使得中央的过道仅能容一人通过。
    大街上有n个扭曲的改改人从各自的位置出发,想要到自己选定好的位置进行传教活动。
    这本来是件小事,但是中国有一句古话,叫做一万个罚吹心中有一万部罚抄,所以如果俩改改人在路上相遇的话就会上演全武行..
    幸好新岛老贼在大街两端留了足够的空间,改改人们可以先走到两端,再一个个走到目标位置。
    大街长度为L,两端分别是x=0x=L,第i个改改人一开始在x=S_{i},想要走到x=T_{i}
    显然肯定存在合法的方案使得全程不会有俩改改人在不是端点的地方相遇。
    新岛老贼想知道所有改改人移动长度总和的最小值,不然他就会把你的mz写死(

输入格式

    多组数据。第一个整数T表示数组组数。

    对于每组数据:

      第一行俩整数n和L。

      接下来有n行,每行俩整数,第i+1行的两个数分别表示S_{i}T_{i}

输出格式

    对于每组数据输出一行一个整数,表示移动距离之和的最小值。

样例输入1

1
2 10
3 8
9 6

样例输出1

14

样例输入2

1
4 20
6 13
11 4
5 7
12 14

样例输出2

48

数据范围与约定

  • 1leq nleq 100,2leq Lleq 10^6,1 leq S_{i},T_{i} leq L-1,1leq T leq 50,保证同组数据里,S_{i}各不相同,T_{i}各不相同。

样例解释1

第二个人走到右端,第一个人走到右端,第二个人走到自己的目的地,第一个人走到自己的目的地。

样例解释2

第3、1、2个人依次走到左端,第4、1、3、2个人依次走到目的地。

这道题以前写过题解hh

网络流题解

贪心题解

两个看一个就行了 不过贪心确实跑得比较快 原题是51nod的狭窄的通道 有兴趣做做哇 题目传送门

T3

M SRM 04

描述

给 n 个数 A_{1..n},有 Q 个询问 [L,R],每次求出有多少二元组 (x,y) 同时满足 L leq x < y leq R 和 A_x geq A_y

输入格式

第一行两个整数 n 和 Q

第二行 n 个整数 A_{1..n}

接下来 Q 行,每行代表一次询问,每行有两个整数为 L 和 R

输出格式

对于每次询问,依次输出其所得到的值

样例输入

3 2
3 2 1
1 2
1 3

样例输出

1
3

数据范围与约定

  • 1leq nleq 1000
  • 1leq Qleq 100000
  • 0 < A_i < 2^{32}
  • 有坑点,请仔细阅读题目

T3我是最后写的因为考虑到有坑点qwq 但是最后发现确实有坑点因为std错了.....最后重测才Ac的 也是还了个愿吧

这道题正解应该是树状数组求逆序数对 但是我不会哇 233 所以就n2暴力写了一波 还好没被卡

sum【i】【j】就是i这个数到j(可前可后)有多少个符合条件的数和他组成数对 这样就可以o(n2)预处理然后0(1)查询了

#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
LL read(){
    LL ans=0,f=1,c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();}
    return ans*f; 
}
LL n,q,x,y;
LL v[1007]; 
int sum[1007][1007],f[1007][1007];
int main()
{
    n=read(); q=read();
    for(int i=1;i<=n;i++) v[i]=read();
    for(int i=1;i<=n;i++){
        for(int j=i-1;j;j--){
            sum[i][j]=sum[i][j+1];
            if(v[j]>=v[i]) sum[i][j]++;
        }
        for(int j=i+1;j<=n;j++){
            sum[i][j]=sum[i][j-1];
            if(v[i]>=v[j]) sum[i][j]++;
        }
    }
    //printf("%d
",f[0][0]);
//    for(int i=1;i<=n;i++,printf("
"))  for(int j=1;j<=n;j++) printf("[%d] ",sum[i][j]);
    for(int l=1;l<n;l++)
        for(int r=l+1;r<=n;r++)
            f[l][r]=f[l][r-1]+sum[r][l];
    //printf("%d
",f[1][2]);
    //printf("%d
",sum[2][1]);
    while(q--){
        x=read(); y=read(); //printf("[%lld %lld]
",x,y); printf("%d
",f[1][2]);
        x=max(1LL,x); y=min(n,y);
        if(x>=y) printf("0
");
        else printf("%d
",f[x][y]);
    }
    return 0;
}
View Code

T4

A SRM 04

描述

给个整数 n,你需要算出这个数在二进制下有多少组连续的 1

输入格式

一个整数 n

输出格式

一个整数,表示连续的 1 的组数

样例输入

5

样例输出

2

数据范围与约定

  • 0 leq n leq 10^{18}

样例解释

5 在二进制下是 101,组数为 2

这道题就是一波匹配就解决问题了

#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
LL read(){
    LL ans=0,f=1,c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();}
    return ans*f; 
}
LL n,ans;
bool f;
int main()
{
    n=read(); 
    while(n){
        while((n&1)&&n) f=1,n>>=1;
        if(f) ans++;
        while(!(n&1)&&n) n>>=1;
    }
    printf("%lld",ans);
    return 0;
}
View Code

T5

K SRM 04

描述

一个序列满足条件是指其众数在序列中的出现次数不小于 frac{len}{2}(len 为序列长度)。

给定长度为 n 的序列 A,问 A 中有多少连续子序列满足条件。

输入格式

第一行一个整数 n

第二行 n 个整数 A_{1..n}

输出格式

一个整数,表示满足条件的连续子序列数。

样例输入

7
1 2 3 3 2 1 3

样例输出

11

数据范围与约定

  • 1leq nleq 1000
  • 1leq A_ileq 10^9

样例解释

在样例中满足条件的连续子序列有:A[1...1]、A[2...2]、A[3...3]、A[4...4]、A[5...5]、A[6...6]、A[7...7]、A[3...4]、A[2...4]、A[3...5]、A[3...7]。

这道题我用了离散化每个数的值来实现桶排然后就枚举区间 每次加一个数就更新一波众数就可以啦

#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
const int mod=23333333;
using namespace std;
int read(){
    int ans=0,f=1,c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();}
    return ans*f; 
}
int n;
int v[5007];
int first[mod],sum[1007];
LL ans,cnt;
struct node{int v,next;}e[5007];
int get(int x){
    int w=x%mod;
    for(int i=first[w];i;i=e[i].next) if(e[i].v==x) return i;
    cnt++; e[cnt].v=x; e[cnt].next=first[w]; first[w]=cnt;
    return cnt;
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++) v[i]=read();
    for(int i=1;i<=n;i++){
        int k,mx=0;
        memset(sum,0,sizeof(sum));
        for(int j=i;j<=n;j++){
            k=get(v[j]); sum[k]++; 
            mx=max(mx,sum[k]);
            if(mx>(j-i+1)/2) ans++;
        }
    }
    printf("%lld
",ans);
    return 0;
}
View Code

 到这里这次比赛就圆满了(写完脑(nai)子疼) 这次也算发挥得不错吧 下次还是得被唐神葱神以及岚清大爷踩啊......祝我好运吧.

原文地址:https://www.cnblogs.com/lyzuikeai/p/7144082.html