码迷,mamicode.com
首页 > 其他好文 > 详细

CF1486X Codeforces Round #703

时间:2021-02-20 12:36:33      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:out   中位数   sed   str   puts   大于等于   构造   fine   getx   

C2 Guessing the Greatest (二分+构造)

题目大意:交互题,每次可以询问一个子区间次大值的位置,最多询问20次,问全局最大值的位置。n=1e5

40次的情况大力二分,20次需要一些技巧

设全局最大值位置为$x$

问一次全局次大值,设为$pos$,再次询问$pos$两侧判断最大值在$pos$左侧还是右侧,并把$pos$它放在后续处理区间的头或者尾

放在头/尾可以减少很多麻烦

现假设$pos$在尾,我们在$[1,pos-1]$里找$x$

每次二分一个位置$mid$,如果$mid\le x$,那么问$[mid,pos]$结果是$pos$,如果$mid>x$,结果不是$pos$

如此可找到x

技术图片
 1 const int N1=105; const int inf=0x3f3f3f3f;
 2 
 3 int n,now;
 4 int getx(int l,int r)
 5 {
 6     if(l==r) return 0;
 7     printf("? %d %d\n",l,r);
 8     fflush(stdout);
 9     int x; scanf("%d",&x); return x; 
10 }
11 void solveL(int pos)
12 {
13     int l=1,r=pos-1,mid,ans=0,k;
14     while(l<=r)
15     {
16         mid=(l+r)>>1;
17         k=getx(mid,pos);
18         if(k==pos) ans=mid, l=mid+1;
19         else r=mid-1;
20     }
21     printf("! %d\n",ans); exit(0);
22 }
23 void solveR(int pos)
24 {
25     int l=pos+1,r=n,mid,ans=0,k;
26     while(l<=r)
27     {
28         mid=(l+r)>>1;
29         k=getx(pos,mid);
30         if(k==pos) ans=mid, r=mid-1;
31         else l=mid+1;
32     }
33     printf("! %d\n",ans); exit(0);
34 }
35 
36 int main()
37 {
38     scanf("%d",&n);
39     int pos=getx(1,n),k;
40     if(pos==1) solveR(1);
41     else if(pos==n) solveL(n); 
42     else{
43         k=getx(1,pos);
44         if(k==pos) solveL(pos); else solveR(pos);
45     }
46     return 0;
47 }
View Code

 

 

Max Median (二分+数据结构)(中位数问题)

题目大意:给出一个序列,问所有长度大于等于k的子区间中,中位数的最大值是多少,$n=2e5$

题解给了这样一个妙妙思路:

首先考虑序列都是1和-1咋做:权值和大于0的子区间的中位数是1!需要维护小于某个值的最小位置,树状数组记录前缀最小值

推广到中位数问题,二分。

每次判断中位数$\ge mid$是否可行

把小于$mid$填成-1,$\ge mid$填成1,权值和大于0的子区间的中位数$\ge mid$!和上面同样的方法做就行了

技术图片
 1 const int N1=400010; const int inf=0x3f3f3f3f;
 2 
 3 int n,K,nn;
 4 int a[N1],sum[N1];
 5 struct bit{
 6 int mi[N1];
 7 void upd(int x,int w)
 8 { for(int i=x;i<=nn;i+=i&(-i)) mi[i]=min(mi[i],w); }
 9 int query(int x)
10 { int ans=inf; for(int i=x;i;i-=i&(-i)) ans=min(ans,mi[i]); return ans; }
11 void clr(int x)
12 { for(int i=x;i<=nn;i+=i&(-i)) mi[i]=inf; }
13 }s;
14 int check(int w)
15 {
16     memset(s.mi,0x3f,sizeof(s.mi));
17     s.upd(n+1+0,0);
18     for(int i=1,j;i<=n;i++) 
19     {
20         if(a[i]<w) sum[i]=sum[i-1]-1; else sum[i]=sum[i-1]+1;
21         j=s.query(n+1+sum[i]-1);
22         if(i-j>=K) return 1;
23         s.upd(n+1+sum[i],i);
24     }
25     return 0;
26 }
27 
28 int main()
29 {
30     scanf("%d%d",&n,&K); nn=n+n+1;
31     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
32     int l=1,r=n,ans=0,mid;
33     while(l<=r)
34     {
35         mid=(l+r)>>1;
36         if(check(mid)) ans=mid, l=mid+1;
37         else r=mid-1;
38     }
39     printf("%d\n",ans);
40     return 0;
41 }
View Code

 

 

Paired Payment (图上构造)

题目大意:给一个无向图,每次必须连着走两条边,代价为$(w1+w2)^{2}$,问从1走到其它所有点的代价最小值,$n=1e5,w\le 50$

又是一道构造妙妙题目

由于$w$很小,考虑拆点

对于一条有向边$(u,v,w)$

i是和v相连的出来的所有不同权值,$u->(v,i)$,代价$(w+i)^{2}$。 $ (u,w)->v$,代价0

考虑连着走两条边$(x,y,w1)(y,z,w2)$的情形:$x->(y,w2)->z$ 代价为$(w1+w2)^{2}$

然后最短路就行了,边数为$O(Wm)$,时间复杂度$O(Wmlogm)$

用map维护拆点可以减少点数

技术图片
 1 #define ite map<int,int>::iterator
 2 const int N1=500005; const int M1=N1*42; const ll inf=0x3f3f3f3f3f3f3f3fll;
 3 
 4 struct edge{
 5 int to[M1],nxt[M1],val[M1],head[N1],cte;
 6 int ae(int u,int v,int w)
 7 { cte++; to[cte]=v, nxt[cte]=head[u]; head[u]=cte; val[cte]=w; }
 8     // printf("%d %d %d\n",u,v,w); 
 9 }e;
10 struct node{
11 int id; ll val;
12 friend bool operator < (const node &s1,const node &s2)
13 { return s1.val>s2.val; }
14 };
15 priority_queue<node>que;
16 
17 int n,m,tot;
18 int id[N1]; ll dis[N1]; bool vis[N1];
19 map<int,int>mp[N1];
20 void addmp(int u,int v,int w)
21 {
22     ite k=mp[v].find(w); int y;
23     if(k==mp[v].end()) y=++tot, mp[v][w]=tot;
24     else y=(*k).second;
25     e.ae(y,u,0);
26 }
27 void adde(int u,int v,int w1)
28 {
29     int y,w2;
30     for(ite k=mp[v].begin();k!=mp[v].end();k++)
31     {
32         w2=(*k).first; y=(*k).second;
33         e.ae(u,y,(w1+w2)*(w1+w2));
34     }
35 }
36 void dijkstra()
37 {
38     int x,j,v; node tmp;
39     memset(dis,0x3f,sizeof(dis)); 
40     que.push((node){1,0}); dis[1]=0; 
41     while(!que.empty())
42     {
43         tmp=que.top(); que.pop(); x=tmp.id;
44         if(vis[x]) continue; vis[x]=true;
45         for(j=e.head[x];j;j=e.nxt[j])
46         {
47             v=e.to[j];
48             if(dis[v]>dis[x]+e.val[j])
49             {
50                 dis[v]=dis[x]+e.val[j];
51                 que.push((node){v,dis[v]});
52             }
53         }
54     }
55 }
56 int ex[N1],ey[N1],ew[N1];
57 
58 int main()
59 {
60     scanf("%d%d",&n,&m);
61     tot=n;
62     for(int i=1;i<=m;i++) 
63     {
64         scanf("%d%d%d",&ex[i],&ey[i],&ew[i]);
65         addmp(ex[i],ey[i],ew[i]); addmp(ey[i],ex[i],ew[i]);
66     }
67     for(int i=1;i<=m;i++)
68     {
69         adde(ex[i],ey[i],ew[i]); adde(ey[i],ex[i],ew[i]);
70     }
71     dijkstra();
72     for(int i=1;i<=n;i++) 
73         if(dis[i]<inf) printf("%lld ",dis[i]);
74         else printf("-1 ");
75     puts("");
76     return 0;
77 }
View Code

 

CF1486X Codeforces Round #703

标签:out   中位数   sed   str   puts   大于等于   构造   fine   getx   

原文地址:https://www.cnblogs.com/guapisolo/p/14418650.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!