XXII Open Cup named after E.V. Pankratiev, Grand Prix of IMO E. Eulerian?
交互题
题目大意:给你一张图,在每一次的询问中,你可以询问每个子图包含多少条边,最多询问60次。问给你的图是不是欧拉图
基本思路:设原图中边的总个数为 s u m sum sum,
如果把原图分成两个子图 G 1 , G 2 G1,G2 G1,G2, G 1 G1 G1包含的边个数为 s 1 s1 s1, G 2 G2 G2包含边的个数为 s 2 s2 s2。可以发现如果原图为欧拉图,可以发现构成两个子图后剩下的边 s u m − s 1 − s 2 sum-s1-s2 sum−s1−s2必为偶数。若不是偶数,则不存在一条回路能经过所有的边,即不是欧拉图。故在询问原图的边数之后,随机将图中的点分成两份,得到 k = s u m − s 1 − s 2 k=sum-s1-s2 k=sum−s1−s2,这样询问29次,如果存在一个 k i k_{i} ki使得 k i k_{i} ki为奇数,则原图一定不是欧拉图。
这种方法出错的概率为 1 2 29 \frac{1}{2 ^ {29}} 2291
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long int
int sum;
int n;
bool f;
void ask()
{
vector<int> s(n + 1);
for (int i = 1; i <= n;i++)
s[i] = rand()% 2;
int a1, a2, cnt1=0, cnt2=0;
for (int i = 1; i <= n;i++)
{
if(s[i]%2==0)
cnt2++;
else
cnt1++;
}
//cout<<cnt1<<" "<<cnt2<<endl;
cout << "? " << cnt1 << " ";
for (int i = 1; i <= n;i++)
{
if(s[i]==1)
cout << i << " ";
}
cout << endl;
cin >> a1;
cout << "? " << cnt2 << " ";
for (int i = 1; i <= n; i++)
{
if (s[i] == 0)
cout << i << " ";
}
cout << endl;
cin >> a2;
int left = sum - a1 - a2;
if(left%2==1)
f = true;
}
signed main()
{
srand(time(NULL));
cin >>n;
cout << "? " << n << " ";
for (int i = 1; i <= n;i++)
cout << i << ' ';
cout << endl;
cin >> sum;
for (int i = 1; i <= 29;i++)
ask();
if(f)
cout << "! NO" << endl;
else
cout << "! YES" << endl;
return 0;
}