CCF-NOIP-2018 提高组(复赛) 模拟试题(五)

T1 相遇

【问题描述】

在一场奇怪的梦里,小 Y 来到了一个神奇的国度。这个国度可以用一根数轴表示,小 Y 在 N 处,而小 Y 想吃的美食在 K 处。小 Y 有两种方式移动, 一种叫做步行, 一种叫做瞬移。 对于每次步行操作,小 Y 可以从x移动到 x + 1 或者 x – 1, 而对于每次瞬移操作小 Y 可以从 x 瞬移到2x。那么小 Y 最少要移动多少次才能到达 K 处吃到食物呢?

【输入格式】

仅有两个整数 NK

【输出格式】

共一行,包含一个整数,表示最少的移动次数

【样例1】

样例输入
5 17
样例输出
4

数据规模与约定

0 ≤ N, K ≤ 100,000

题解

方法很多,然而考试时本蒟蒻只想到了DP的做法。我们设f[i]表示从ni的最短路径,此时我们已经可以得知所有\forall i \le n时的情况,因为当当前位置大于想要到达的位置时,我们只能通过每次移动到x-1来逐步逼近位置,即:f[i] = \begin{cases} 0 & i=n \\ f[i+1]+1 & i < n \end{cases}
此时我们发现,当i>n时,任意一个f[i]都可以通过f[i-1]到达。特殊的,当i为偶数时,每个f[i]位置都可以经由f[i/2]到达。同时,我们仍然需要考虑f[i]=f[i-1]的情况。事实上若i为偶数时并不需要考虑,因为从f[i+1]到达f[i]的步骤必然要大于从min(f[i/2],f[i-1])到达的步骤(可以想想为什么)而当i为奇数时,我们可以考虑取从f[i-1]到达f[i]所需步骤和从f[(i+1)/2]到达f[i]的步骤的最小值。因此,我们的转移方程为:
f[i] = \begin{cases} 0 & i=n\\ f[i+1]+1 & i<n\\ min(f[i/2]+1,f[i-1]+1) & i>n,i\%2=0\\ min(f[(i+1)/2]+2,f[i-1]+1) & i>n,i\%2=1 \end{cases}
ps:本蒟蒻的dp水平极低,因此推出的式子极为冗长,但是整体思维层次不高,毕竟本蒟蒻都能AC
代码如下:

#include<bits/stdc++.h>
#define maxn 100000
using namespace std;
long long n,k;
long long f[maxn];
int main(){
    //freopen("meet.in","r",stdin);
    //freopen("meet.out","w",stdout);
    scanf("%d%d",&n,&k);
    f[n]=0;
    for(register long long i=n-1;i>=0;i--)f[i]=f[i+1]+1;
    for(register long long i=n+1;i<=k;i++){
        if(i%2==0){
            f[i]=min(f[i/2]+1,f[i-1]+1);
        }
        else f[i]=min(f[i-1]+1,f[(i+1)/2]+2);
        //cout<<i<<":"<<f[i]<<endl;
    }
    //for(register long long i=0;i<=n;i++)cout<<i<<":"<<f[i]<<endl;
    cout<<f[k]<<endl;
    return 0;
}

T2 秘密邮件

【问题描述】

A收到了一封来自外星球的秘密邮件。邮件由n个大写英文字母组成,不巧的是小A收到邮件以后一不小心打乱了原来的字母顺序。但是聪明的小A记住了原邮件的完整内容, 现在她每次可以选择打乱后邮件中相邻的两个字母进行交换,问最少交换多少次能够将打乱的邮件恢复成原邮件

【输入格式】

第一行一个整数n表示邮件的长度。
第二行一个长度为n的只包含大写字母的字符串表示打乱后的邮件 。
第三行一个长度为n的只包含大写字母的字符串表示原邮件 。
为保证打乱后的邮件可以恢复成原邮件,所有的测试数据满足任意一种大写字母在两封邮件中的出现次数相同。

【输出格式】

共一行包含一个整数,表示最少的交换次数。

【样例1】

样例输入
4
ABCD
DBCA
样例输出
5

数据规模与约定

n \le 1,000,000

题解

蒟蒻的我考试时竟然只写了60分的暴力代码QAQ事实上,这道题比T1还要简单。我们只需要给第二个字符串中每个字符一个哈希值,并将这个哈希值带入第一个字符串中,求一下逆序对的数量即可!
贴出代码QAQ

#include <bits/stdc++.h>
using namespace std;
long long a[1000100],b[1000100],ans = 0;
long long n;
void merge_sort(long long l,long long r){
    long long p1,p2,p,mid;
    if(l == r){
        return ;
    }
    mid = (l+r) >> 1;
    merge_sort(l,mid);
    merge_sort(mid+1,r);
    p1 = l,p2 = mid+1,p = 0;
    while(p1 <= mid || p2 <= r){
        if(p1 <= mid && (p2 > r || a[p1] <= a[p2])){
            b[++p] = a[p1];
            p1++;
        }else{
            b[++p] = a[p2];
            p2++;
            ans += mid-p1+1;
        }
    }
    for(long long i = 1;i <= p;i++){
        a[l+i-1] = b[i];
    }
}
int main(){
    //freopen("letter.in","r",stdin);
    //freopen("letter.out","w",stdout);
    cin >> n;
    string A,B;
    cin >> A >> B;
    queue<int> q[26];
    for(int i = 0;i < A.size();i++){
        q[(int)(A[i]-'A')].push(i+1);
    }
    for(int i = 0;i < B.size();i++){
        a[i+1] = q[(int)(B[i]-'A')].front();
        q[(int)(B[i]-'A')].pop();
    }
    ans = 0;
    merge_sort(1,n);
    cout << ans;
    return 0;
}

T3 小乔

【问题描述】

恋之微风·小乔,是手游《王者荣耀》中的法师型英雄,擅长远程消耗。小乔有一把神奇的扇子,借助灵活的走位可以对敌人造成高额的伤害。小乔是小A最喜欢(会玩)的英雄之一。在一场梦里,小A与小乔来到了一个异次元世界。异次元世界位于极坐标系中。小乔定义了一个值m,以等分[-π,π]弧度(详见样例) 。小乔还有一把神奇的扇子,她将进行n次“绽放之舞”操作。对于第i次"绽放之舞”操作,小乔将设定半径r_i,起始位置s_i,终止位置t_i,她借助自己神奇的扇子,以坐标系原点为圆心,)r_i为半径,将圆心角\frac{πs_i}{m}到圆心角\frac{πt_i}{m}这部分扇形区域逆时针叠加一层“治愈微笑” 。
小乔想到了一个有趣(奇怪)的问题,她希望知道有多大面积的区域被叠加过至少2层“治愈微笑” 。这个问题难倒了平日里善于发现并解决问题的小 A。现在小 A 求助于你,希望你能帮他解决这个问题。我们设答案的值为T,为了方便表达,你只需要输出T*\frac{2m}{π}(可以证明这是一个非负整数)的值即可。

【输入格式】

第一行是三个整数n,m,k
接下来n行,依次描述每个“绽放之舞”操作,每行包含三个整数r_i,s_i,t_i

【输出格式】

输出只包含一个整数,表示T*\frac{2m}{π}的值。

【样例输入1】

3 8 2
1 -8 8
3 -7 3
5 -5 5

【样例输出1】

样例输出
76
image

【数据规模与约定】

1\le n \le 100000,1 \le m \le 10^5

【题解】

原谅我浅薄的几何知识。


image
#include <bits/stdc++.h>
#define mp make_pair
#define fi first
#define se second
 
using namespace std;

typedef long long int64;
const int MAXN=400005;

int n,m,lim;
int na,nb;

struct A{
    int l,r,R;
    A(void){}
    A(int _l,int _r,int _R):l(_l),r(_r),R(_R){}
    inline void print()
    {
        printf("l = %d, r = %d, R = %d.\n",l,r,R);
    }
}a[MAXN],b[MAXN];

struct B{
    int p,r;
    bool f;
    #define SHANCHU 0
    #define CHARU 1
    B(void){}
    B(int _p,int _r,bool _f):p(_p),r(_r),f(_f){}
    friend bool operator < (const B &a,const B &b)
    {
        return a.p<b.p;
    }
}eve[MAXN];
int elen;

struct Size_Balanced_Tree{
    int left,right,size,data;
}SBT[MAXN*5];
int pn,root;

inline void left_rotate(int &p)
{
    int k=SBT[p].right;
    SBT[p].right=SBT[k].left;
    SBT[k].left=p;
    SBT[k].size=SBT[p].size;
    SBT[p].size=SBT[SBT[p].left].size+SBT[SBT[p].right].size+1;
    p=k;
}

inline void right_rotate(int &p)
{
    int k=SBT[p].left;
    SBT[p].left=SBT[k].right;
    SBT[k].right=p;
    SBT[k].size=SBT[p].size;
    SBT[p].size=SBT[SBT[p].left].size+SBT[SBT[p].right].size+1;
    p=k;
}

void maintain(int &p,bool f)
{
    if (!f)
    {
        if (SBT[SBT[SBT[p].left].left].size>SBT[SBT[p].right].size) right_rotate(p);
        else if (SBT[SBT[SBT[p].left].right].size>SBT[SBT[p].right].size) left_rotate(SBT[p].left),right_rotate(p);
        else return;
    }
    else
    {
        if (SBT[SBT[SBT[p].right].right].size>SBT[SBT[p].left].size) left_rotate(p);
        else if (SBT[SBT[SBT[p].right].left].size>SBT[SBT[p].left].size) right_rotate(SBT[p].right),left_rotate(p);
        else return;
    }
    maintain(SBT[p].left,0);
    maintain(SBT[p].right,1);
    maintain(p,0);
    maintain(p,1);
}

void Insert(int &p,int v)
{
    if (!p)
    {
        p=++pn;
        SBT[p].left=SBT[p].right=0;
        SBT[p].size=1;
        SBT[p].data=v;
    }
    else
    {
        SBT[p].size++;
        if (v<SBT[p].data) Insert(SBT[p].left,v);
        else Insert(SBT[p].right,v);
        maintain(p,v>=SBT[p].data);
    }
}

int Delete(int &p,int v)
{
    SBT[p].size--;
    int k=SBT[p].data;
    if (v==k||(v<k&&!SBT[p].left)||(v>k&&!SBT[p].right))
    {
        if (!SBT[p].left||!SBT[p].right) p=SBT[p].left+SBT[p].right;
        else SBT[p].data=Delete(SBT[p].left,v+1);
        return k;
    }
    else
    {
        if (v<k) return Delete(SBT[p].left,v);
        else return Delete(SBT[p].right,v);
    }
}

inline int Find_Kth(int k)
{
    int p=root;
    while (SBT[SBT[p].left].size+1!=k)
    {
        if (SBT[SBT[p].left].size+1<k) k-=SBT[SBT[p].left].size+1,p=SBT[p].right;
        else p=SBT[p].left;
    }
    return SBT[p].data;
}

inline int64 work(A *a,int n)
{
    pn=root=elen=0;
    for (int i=1;i<=n;i++)
    {
        eve[++elen]=B(a[i].l,a[i].R,CHARU);
        eve[++elen]=B(a[i].r,a[i].R,SHANCHU);
    }
    sort(eve+1,eve+elen+1);
    int64 res=0;
    int last=eve[1].p;
    int l=1,r=1;
    while (l<=elen)
    {
        while (r<=elen&&eve[r].p==eve[l].p) r++;
        if (SBT[root].size>=lim)
        {
            int64 x=Find_Kth(SBT[root].size-lim+1);
            res+=x*x*(eve[l].p-last);
        }
        for (int i=l;i<r;i++)
        {
            if (eve[i].f==CHARU) Insert(root,eve[i].r);
            else Delete(root,eve[i].r);
        }
        last=eve[l].p;
        l=r;
    }
    return res;
}

int main()
{
    //freopen("xiaoqiao.in","r",stdin);
    //freopen("xiaoqiao.out","w",stdout);
    scanf("%d%d%d",&n,&m,&lim);
    for (int i=1;i<=n;i++)
    {
        int R,l,r;
        scanf("%d%d%d",&R,&l,&r);
        if (l==m) l=-m;
        if (r==-m) r=m;
        if (l==r) continue;
        if (l<=0&&r<=0)
        {
            if (l<r) a[++na]=A(l,r,R);
            else if (l>r)
            {
                if (l!=0) a[++na]=A(l,0,R);
                if (-m!=r) a[++na]=A(-m,r,R);
                if (0!=m) b[++nb]=A(0,m,R);
            }
        }
        else if (l>=0&&r>=0)
        {
            if (l<r) b[++nb]=A(l,r,R);
            else if (l>r)
            {
                if (l!=m) b[++nb]=A(l,m,R);
                if (0!=r) b[++nb]=A(0,r,R);
                if (-m!=0) a[++na]=A(-m,0,R);
            }
        }
        else if (l<=0&&r>=0)
        {
            if (l!=0) a[++na]=A(l,0,R);
            if (0!=r) b[++nb]=A(0,r,R);
        }
        else if (l>=0&&r<=0)
        {
            b[++nb]=A(l,m,R);
            a[++na]=A(-m,r,R);
        }
    }
    printf("%lld\n",work(a,na)+work(b,nb));
    return 0;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,186评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,858评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,620评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,888评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,009评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,149评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,204评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,956评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,385评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,698评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,863评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,544评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,185评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,899评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,141评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,684评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,750评论 2 351