10.30 NOIP模拟赛(afternoon)

- 他

【问题描述】

一张长度为n的纸带,我们可以从左至右编号为0-n(纸带最左端标号为
0)。现在有m次操作,每次将纸带沿着某个位置进行折叠,问所有操作之后纸带
的长度是多少。

【输入格式】

第一行两个数字你,m如题意所述。
接下来一行m个整数代表每次折叠的位置。

【输出格式】

一行一个整数代表答案。

【样例输入】

5 2
3 5

【样例输出】

2

【样例解释】

树上有只鸟。

【数据规模与约定】

对于60%的数据,n,m≤3000。
对于100%的数据,n≤10^18 ,m≤3000。

思路:

对于60%的数据可以用并查集来做
每次把折叠后小的一段去掉
再把去掉的一段上的点与保留的一段上的点对应起来
用 并茶几 建立关系

对于100%的数据 先把m次操作存起来离线处理
每次操作后,将去掉的那一段的点直接修改成当前
还在纸条上的点
例如
长度为8的点从5这里折叠,
显然去掉6-8的段 那么将之后操作中的6-8的数字改为2-4
对应修改就可以
这里修改的数字都是m次操作中要折叠的地方
用数组记录一下就可以了

代码

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
unsigned long long n,p[3010],start,end;
int m;
int main()
{
    freopen("he.in","r",stdin);
    freopen("he.out","w",stdout);
    cin>>n>>m;
    for(int i=1;i<=m;i++) cin>>p[i];
    start=0;
    end=n;
    for(int i=1;i<=m;i++)
        if((p[i]-start)>=(end-p[i]))
        {
            n=n-(end-p[i]);
            end=p[i];
            for(int j=i+1;j<=m;j++)
                if(p[j]>end)
                    p[j]=p[i]-(p[j]-p[i]);
        }
        else if((p[i]-start)<(end-p[i]))
        {
            n=n-(p[i]-start);
            start=p[i];
            for(int j=i+1;j<=m;j++)
                if(p[j]<start)
                    p[j]=p[i]+(p[i]-p[j]);
        }
    cout<<n<<endl;
    fclose(stdin);
    fclose(stdout);
    return 0;
}

【问题描述】

给你M,S,L,R求满足L≤ (S×x) mod M≤R最小的正整数想x。

【输入格式】

第一行一个数T代表数据组数。
接下来T行每行四个数代表该组数据的M,S,L,R。

【输出格式】

对于每组数据,输出一行代表答案。如果不存在解,输出“−1” 。

【样例输入】

1
5 4 2 3

【样例输出】

2

【样例解释】

叫南小鸟。

【数据规模与约定】

对于30%的数据,保证有解且答案不超过10^6 。
另外20%的数据,L==R。
对于100%的数据,1≤T≤100,0≤M,S,L,R≤ 10^9 。

正在手敲中...................................

【问题描述】

n个人坐成一圈,其中第n个人拿着一个球。每次每个人会以一定的概率向
左边的人和右边的人传球。当所有人都拿到过球之后,最后一个拿到球的人即为
胜者。求第n个人获胜的概率。 (所有人按照编号逆时针坐成一圈)

【输入格式】

第一行一个数T代表数据组数。
对于每组数据,第一行两个整数n,k如题意所述。
接下来每行一个实数p代表该人将球传给右边的人的概率。

【输出格式】

对于每组数据,一行一个实数代表答案,保留9位小数。

【样例输入】

1
5 1
0.10
0.20
0.30
0.40
0.50

【样例输出】

0.007692308

【样例解释】

然后鸟是我的。

【数据规模与约定】

对于20%的数据,n≤3。
对于70%的数据,T,n≤10。
对于100%的数据,T≤10000,1≤n≤100。

思路:

这题我做的是一脸懵逼,听得也是一脸懵逼
zhw大神说的是等比数列推式子,一脸懵逼
还说可以把传球的人的左右两边直到
最后拿到球的人的中间的人合并成一个人(0.0)我都惊呆了
分求出求出两部分的概率
其实我也不太会,有神犇看出错误请指点

代码:

#include<cstdio>
#define LDB long double
#define DB double
using namespace std;
const int N=1000+10;
int T,n,k,pre[N],next[N];
LDB p[N],q[N];
void deal(int b){
    int a=pre[b],c=next[b];
    LDB pa=p[a],pb=p[b],pc=p[c];
    p[a]=pa*pb/(1-pa*(1-pb));
    q[a]=1-p[a];
    q[c]=(1-pc)*(1-pb)/(1-pb*(1-pc));
    p[c]=1-q[c];
    next[a]=c;pre[c]=a;
}
LDB solve(){
    if(n<=2) return 1;
    if(n<=3) return k==1?p[1]:q[2];
    for(int i=1;i<=n;i++) pre[i]=i-1,next[i]=i+1;
    pre[1]=n;next[n]=1;
    if(k==1){
        for(int i=2;i<n-1;i++) deal(i);
        return p[1];
    }
    if(k==n-1){
        for(int i=2;i<n-1;i++) deal(i);
        return q[n-1];
    }
    for(int i=2;i<n-1;i++) if(i!=k) deal(i);
    deal(k);
    return q[k]*p[1]+p[k]*q[n-1];
}
DB v;
#define name "it"
int main(){
    freopen(name".in","r",stdin);
    freopen(name".out","w",stdout);
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++){
            scanf("%lf",&v);
            p[i]=v;
            q[i]=1-v;
        }
        printf("%.9lf\n",(DB)solve());
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值