CF1498E的xxs解法

solution

这题应该是结论题,什么 Tarjan 什么拓扑序,这不 shaber 题吗,用这些干嘛

看到输出 Yes 后结束则大致可以猜到询问为从大到小猜测所有的解。

那如何在一次交互之后得知该组解合法?

仔细观察题目,猜测一个点必然能到达出度大于等于它的点

证明他!

接下来证明这个结论。

因为原图是一张完全图进行了定向,因此通过入度可以得知出度。

显然,入度小的点的出度一定大于入度大的点

根据抽屉原理,可知出度大的点必然有一条边连向出度小的点或有边指向出度小的点的边

嗯,好像有点抽象。

用图来感性理解一下。

下面的图上点上标的数字为出度

笔者画图功力不高,不喜勿喷

显然,$s$ 所有边可以指向 $t$ 一次可以到达的点集还有剩余,这些边自然就连向 $t$ 和一次可以到达 $t$ 的点集。

而当两点之间出度相同时,若所有出边指向同一点集,则必然不存在这样的图(有两条不同方向的边连接在两点之间)

Q.E.D.

因此将所有点对按入度绝对值之差从大到小排序,一个一个试即可。

code

#include <bits/stdc++.h>
#define f fflush(stdout)
using namespace std;
struct edge{
    int from,to,val;
}x;
int n,i,j,k,m;
struct cmp{
    bool operator()(const edge &x,const edge &y){
        return x.val<y.val;
    }
};
priority_queue<edge,vector<edge>,cmp> h;
int a[505];
string s;
int main() {
    scanf("%d",&n);
    for(i=1;i<=n;i++)
      scanf("%d",&a[i]);
    for(i=1;i<=n;i++)
      for(j=i+1;j<=n;j++){
        int tmp1=i,tmp2=j;
        if(a[tmp1]<a[tmp2]) swap(tmp1,tmp2);
        x.from=tmp1;x.to=tmp2;x.val=a[tmp1]-a[tmp2];
        h.push(x);
      }
    while(!h.empty()){
        x=h.top();h.pop();
        printf("? %d %d\n",x.from,x.to);
        f;
        cin>>s;
        if(s=="Yes"){
            printf("! %d %d\n",x.from,x.to);
            return 0;
        }
    }
    printf("! 0 0");
    return 0;
}
posted @ 2023-09-02 21:38  monster_hunterqwq  阅读(6)  评论(0编辑  收藏  举报  来源