AtCoder Regular Contest 101 F

题目链接:atcoder

考虑所有的洞将数轴划分成了若干个区间,则对每个机器人无论他怎么移动都不可能出这个区间,所以每个机器人至多只可能掉入两个洞中

对于最左边和最右边没有洞的机器人,显然他们的掉洞方案唯一,于是我们不去考虑它,对于剩下的机器人,我们用一个二元组\((l_i,r_i)\)表示它到离它最近的左/右边的洞的距离,很明显一个机器人掉入哪个洞只与操作序列达到的最左边/右边的位置有关。

将所有的二元组放在一个平面上,用它们来标记一些点,操作序列的历史达到的最左边/右边的位置可以用一条只会向上和向右的折线表示。在这条折线下方的点将会落入右边的洞中,在折线上方的点将会落入左边的洞中。

注意到只有当折线的拐角在一个被标记的点的上下发生拐弯时才会引起最终方案的变化。于是我们可以记\(f_i\)表示折线经过的最后一个点为\(i\),且最后折线向右走的方案数,由于上一个拐点只会在\(i\)的左下方,所以不难得到转移方程
\[
f_i=1+\sum_{x_j<x_i,y_j<y_i} f_j
\]

这个形式比较经典,使用树状数组维护\(f\)即可,注意第二维应该按照降序排序避免具有相同的\(x\)和较小的\(y\)的位置会对当前的值产生转移

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<math.h>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double db;
typedef pair<int,int> pii;
const int N=10000;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define fir first
#define sec second
#define mp(a,b) make_pair(a,b)
#define pb(a) push_back(a)
#define maxd 1000000007
#define eps 1e-8
int n,m,tot=0,val[100100],rob[100100],hol[100100],tot1=0;
ll f[100100];
pii p[100100];

struct fenwick_tree{
    int a[100100];

    void modify(int x,int p)
    {
        for (int i=p;i<=tot;i+=lowbit(i)) a[i]=(a[i]+x)%maxd;
    }

    int query(int p)
    {
        int ans=0;
        for (int i=p;i;i-=lowbit(i)) ans=(ans+a[i])%maxd;
        return ans;
    }
}tr;

int read()
{
    int x=0,f=1;char ch=getchar();
    while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
    while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
    return x*f;
}

bool cmp(pii p,pii q) {return ((p.fir<q.fir) || ((p.fir==q.fir) && (p.sec>q.sec)));}

int main()
{
    n=read();m=read();
    rep(i,1,n) rob[i]=read();
    rep(i,1,m) hol[i]=read();
    rep(i,1,n)
    {
        if ((rob[i]<=hol[1]) || (rob[i]>=hol[m])) continue;
        int pos=lower_bound(hol+1,hol+1+m,rob[i])-hol;
        if (hol[pos]==rob[i]) continue;
        p[++tot1]=mp(rob[i]-hol[pos-1],hol[pos]-rob[i]);
        val[++tot]=hol[pos]-rob[i];
    }
    //rep(i,1,n) cout << p[i].fir << " " << p[i].sec << endl;
    sort(val+1,val+1+tot);
    tot=unique(val+1,val+1+tot)-val-1;
    rep(i,1,tot1) p[i].sec=lower_bound(val+1,val+1+tot,p[i].sec)-val;
    sort(p+1,p+1+tot1,cmp);
    tot1=unique(p+1,p+1+tot1)-p-1;
    //cout << endl;
    //rep(i,1,tot1) cout << p[i].fir << " " << p[i].sec << endl;
    rep(i,1,tot1)
    {
        f[i]=tr.query(p[i].sec-1)+1;
        tr.modify(f[i],p[i].sec);
    }
    //rep(i,1,tot1) cout << f[i] << " ";cout << endl;
    ll ans=1;
    rep(i,1,tot1) ans=(ans+f[i])%maxd;
    printf("%lld",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/encodetalker/p/11618875.html

时间: 2024-10-08 14:45:53

AtCoder Regular Contest 101 F的相关文章

AtCoder Regular Contest 101

C题是个傻逼题, 一定是先向右,然后停了或者向左走到某一个点(左边同理)模拟就可以了 D题想了一会才想出来 和tjoi那道排序挺像的 二分答案变0/1来做 刚开始写的时候还把自己作为另外一类搞出来 这样处理挺麻烦的 直接把自己当做比自己大的那一类然后在二分答案时h=mid就可以了 统计答案的时候随便搞个数据结构维护一下就行了 E题比较容易能想到f[i][0/1]表示从i子树中有没有一条路径延伸出来 然后关键就是如何计算这个东西 我们枚举儿子中1的个数 这个是可以dp的 n^2的 然后对于儿子中1

Atcoder Regular Contest 076 F - Exhausted?题解

题目链接:F - Exhausted? 题目大意:有m个椅子在数轴上排列,第i张椅子(1≤i≤m)的坐标为i. 高桥君和他的朋友一共有n个人.高桥君他们因为玩了太久的游戏,大家的腰和背都很痛,所以他们很有必要坐在椅子上休息一下.高桥君他们每个人坐的椅子的坐标都很讲究,第i个人想坐在坐标在li以下(包括li)的椅子上,或者坐在坐标在ri以上(包括ri)的椅子上.当然,一个的椅子只能坐一个人. 可这样计算下去,可能会让他们不能都坐在椅子上休息.青木君关心高桥君他们的健康,尽可能多地增加椅子,让高桥君

AtCoder Regular Contest 068 F - Solitaire

[问题描述] 现在有一个1-n的序列,我们将它依次加入一个双端的序列,加完之后我们再每一次选择双端序列中的左端点/右端点,选择一个将对应的数删除并加入一个删除序列中,问最后有多少个合法的删除序列满足第k个是1(取模1e9+7) [输入格式] 从文件forget.in中读入数据. 一行,n和k. [输出格式] 输出到文件forget.out中. 一行一个整数. [样例输入] [1]17 2 [2]9 1 [3]5 3 [4]2000 1000 [样例输出] [1]262144 [2]128 [3]

AtCoder Regular Contest 101 D - Median of Medians

二分答案 然后前缀和+树状数组来判断这个答案是否大于等于数 如果我们对于一个查询,如果小于这个数令为1,大于这个数领为-1 将所有前缀和放在树状数组中,就可以查询所有sum_{l} < sum_{r}的组合 #include <assert.h> #include <algorithm> #include <bitset> #include <climits> #include <cmath> #include <cstdio>

Atcoder Regular Contest 060 F题第一问答案证明

一切的开始 令 \(x\) 为字符串,\(p\) 为正整数.如果对于满足 \(0\le i<|x|?p\) 的任何整数 \(i\) 满足 \(x[i]=x[i+p]\),则 \(p\) 称为 \(x\) 的周期.\(x\) 的最小周期表示为 \(per(x)\).例如,\(per(abcabcabcab)=3\). 令 \(N\) 为输入字符串 \(w\) 的长度. 情况划分如下: (a)如果 \(w\) 是一个好的字符串(例如 \(w=ababa\)) (b)当 \(per(w)=1\) 时(

AtCoder Regular Contest 098

AtCoder Regular Contest 098 C - Attention 题意 给定一个只包含"E","W"字符串,可以花一的花费使他们互相转换.选定一个位置,使位置左边的字符都变成E,右边都变成W所需要的最小花费. 分析 这题纯粹是签到题,做两个前缀和然后直接加就可以了. #include <iostream> #include <cmath> #include <cstring> #include <cstdi

AtCoder Regular Contest 095

AtCoder Regular Contest 095 C - Many Medians 题意: 有A,B两种匹萨和三种购买方案,买一个A,买一个B,买半个A和半个B,花费分别为a,b,c. 求买X个A和Y个B最小花费使多少. 分析: 明显的发现肯定买性价比更高的方案,分情况讨论一下,如果\(a+b<=2*c\),那么明显的先买足c到A,B中较小的一个,然后再比较一下剩下的那个的单价和\(2*c\)的大小. A[ans=] -->|a+b<=2*c| B(A*a+B*b) A -->

AtCoder Regular Contest 094

AtCoder Regular Contest 094 C - Same Integers 题意: 给定\(a,b,c\)三个数,可以进行两个操作:1.把一个数+2:2.把任意两个数+1.求最少需要几次操作将三个数变为相同的数. 分析: 可以发现如果三个数的奇偶性相同直接加就可以了,对于奇偶性不同的,先把奇偶性相同的两个数都+1,然后按照相同的处理就可以了.可以证明没有更好的方案. #include <bits/stdc++.h> using namespace std; int a,b,c,

AtCoder Regular Contest 103

AtCoder Regular Contest 103 一些吐槽 参加的第一场\(ARC\):一个模拟 + 三个构造 没见过比这更令人感动的题型设置了(简直就是针对我(TAT)) . 感觉全场就我一个人\(E\)题WA了四遍才过....... C-//// 题目大意: 网址 给定一个串\(S\),要求修改一些字符,使得串满足以下条件: \(S_i = S_{i+2}\) \(S_1 \neq S_2\) . 问最少需要修改多少个字符. 题解: 无脑统计一下奇数和偶数格的每种种类. 然后在最大值和