【AIM Tech Round 4 (Div. 2) D Prob】

·题目:D. Interactive LowerBound

·英文题,述大意:

      有一个长度为n(n<=50000)的单链表,里面的元素是递增的。链表存储在一个数组里面,给出长度n、表头在数组的下标和一个值w。题目要求求出链表中大于等于w值的元素中的最小元素。注意,这道题是一道interactive。由于链表是未知的,最多可以进行1999个询问,询问形式:?i。表示询问数组下标为i,询问后,会得到一个答案组(val,Next),表示询问的元素是val,链表下一位所在的数组下标是Next。最终如果找到答案输出:!ans,如果没有找到答案输出:! –1。

分析:

      题目描述有点不准确,文中"没有找到答案"的意思是序链表中不存在满足条件的元素,而不仅仅是询问没找到。

      观察数据范围:50000对1999询问,这看上去是不可能的,因为交互题是询问后就在线回答,大概意思就是你问测评机问题,它回答你……所以这看上去就是在蒙答案,蒙不对就完了(50000这么大,肯定完了)!

      接下来用到随机算法。我们将总数1999拆成a+b。a表示我们先随机生成a个询问,表示在a个询问中最靠近答案的那个向后暴力行走链表b次。上文一句话就概括了本题的做法——为什么这样做是对的?我们将链表从左向右画出来(注意,不是把数组画出来),那么从左向右元素是递增的。我们现在尝试计算可能会遗漏答案情况的概率:

image

      如图,蓝色的点就是随机的点。然后我们会找比val小但是又最近的点,那么向前走链表b次,看看是否找到答案。如果我们不能找到答案,那么由图可知,只有当L>b时,我们的算法是错误的。现在来算一下概率:

      对于一个随机点,它不会落在答案点前面b长度的区间内的概率是:

      P1=(n-b)/n

      那么,由于我们随机了a个点,可得没有点落在答案点前b长度的区间的概率是(这个当然表示我们算法错误的概率啊):

     Pall=((n-b)/n)a

     这个呢,因为啊a+b=1999,我们令x=b,y=1-((n-x)/n)1999-x

     那么可以看出y表示我们的算法能够正确的概率,我们将这个函数分析一下(比如做出图像):

    IZC2V5A~8[QKAUV23DU]4BO

          我们发现当x=1000左右时,y几乎是1了(更精确见图中数据)。所以这道题随机算法竟然可以这样达到美妙!所以我们最终的方法就是:先随机询问 1000个点,然后从最优点走999次,判断答案是否存在了啦啦。

    最后一个代码提醒:这道题直接用rand()会在第六个测试点WA,原因是随机数不均匀,我们需要改成:rand()*rand()*rand()……

    CF型短代码:

    

 1 #include<bits/stdc++.h>
 2 #define _ fflush(stdout)
 3 #define go(i,a,b) for(int i=a;i<=b;i++)
 4 int n,val,a=-1,T,w,Next,l;
 5 int main()
 6 {
 7     srand(time(NULL));
 8     scanf("%d%d%d",&n,&l,&val);
 9     T=1000;while(T--)
10     {
11         printf("? %d
",1ll*rand()*rand()*rand()%n+1);_;
12         scanf("%d%d",&w,&Next);
13         if(w<val&&w>a)a=w,l=Next;
14     }
15     T=999;while(T--)
16     {
17         if(l==-1)break;
18         printf("? %d
",l);_;
19         scanf("%d%d",&w,&Next);l=Next;
20         if(w>=val){printf("! %d
",w);_;return 0;}
21     }
22     puts("! -1");_;return 0;
23 }//Paul_Guderian

    

又一种信仰将要破灭,又一个时代将要来临.———汪峰《风暴来临》
原文地址:https://www.cnblogs.com/Paul-Guderian/p/7458036.html