Problem - B - Codeforces
题意:
给定一个序列,让你判断是否存在两个子序列使得这两个子序列或起来相等
思路:
设两个子序列是a和b
两个子序列凭空出现,那肯定考虑构造
满足的条件是:
a!=b
f(a)=f(b)
如果只考虑第二个条件,那么特解是a=b
但是考虑到a不能等于b,因此考虑把一些数删掉,使得删掉数后f(a)依然等于f(b)
删掉的这些数满足什么条件呢?满足这个数是可有可无的数
可有可无的数就是删掉之后f(a)依然等于f(b),即二进制位为1的位的1的个数在删之前>=2
因此a就是所有数或起来,b就是a集合去掉可有可无的数
所以结论就是,如果一个数列,它没有可有可无的数,那就不行,否则就可以
以上讨论的是取a为所有数或起来的情况,那么怎么考虑一般情况
事实上是可以证明,所有的一般情况都可以转化为上面讨论的那种情况
这里贴一下pzr大佬的证明:
Code:
#include <bits/stdc++.h>
using namespace std;
const int mxn=2e5+10;
map<int,int> cnt;
vector<int> v[mxn];
int n,k,x;
void solve(){
cnt.clear();
cin>>n;
for(int i=1;i<=n;i++) v[i].clear();
for(int i=1;i<=n;i++){
cin>>k;
for(int j=1;j<=k;j++){
cin>>x;
v[i].push_back(x);
cnt[x]++;
}
}
for(int i=1;i<=n;i++){
int ok=1;
for(auto it:v[i]){
if(cnt[it]<2) ok=0;
}
if(ok){
cout<<"Yes"<<'\n';
return;
}
}
cout<<"No"<<'\n';
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int __=1;cin>>__;
while(__--)solve();return 0;
}
总结:
一些证明怎么去证明:
如果我们要去证明结论的正确性,就去考虑一般的情况,然后看这个一般的情况能不能转化到我们所考虑的特殊情况
一般性证明:直接设未知数,然后考虑直接证
反证法
归纳法
2.构造,先考虑需要满足的条件,然后去考虑特解情况