首先必须要知道的是:
x + y = x A N D y + x O R y x+y=xANDy+xORy x+y=xANDy+xORy
然后就可以发现操作结束后总和不会变。
然后显然可以发现这些数应该使得大的尽可能大,这样才能满足 ∑ i = 1 n a i 2 \sum_{i=1}^n a_i^2 i=1∑nai2
尽可能大。
然后做法就显然了,对于操作 i , j i,j i,j,其实就是把 a i a_i ai所拥有的 a j a_j aj没有的bit移给 a j a_j aj。
code:
#include
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a
#define KEEP while(1)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define debug_pair(A) cerr<
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
typedef pair<mp,mp> superpair;
int cnt[31];
int main(){
fastio;
int n;
cin>>n;
rb(i,1,n)
{
int ai;
cin>>ai;
rep(j,31){
if(ai&(1<<j))
{
cnt[j]++;
}
}
}
LL res=0;
rb(i,1,n){
LL ai=0;
rep(j,31){
if(cnt[j]){
ai+=1<<j;
cnt[j]--;
}
}
res+=ai*ai;
}
cout<<res<<endl;
return 0;
}
*把边反过来:所有的点的入度 ≤ 2 \leq 2 ≤2 *
从前往后考虑,考虑第i个,如果以这个点开始存在一条dangerous path 就关闭这个点。
这样会删掉多少个点呢?
首先,先分一个组。
对于删掉后的图,如果从一个点走出去最多走出去1个(包括这个点)则分到组 G 1 G_1 G1如果2个分到组 G 2 G_2 G2,剩下删掉的分到 G 3 G_3 G3。
由于每一给点的入度 ≤ 2 \leq 2 ≤2所以, ∣ G 2 ∣ ≥ ∣ G 3 ∣ / 2 |G_2|\geq|G_3|/2 ∣G2∣≥∣G3∣/2,同理 ∣ G 1 ∣ ≥ ∣ G 2 ∣ / 2 |G_1|\geq|G_2|/2 ∣G1∣≥∣G2∣/2,由于 ∣ G 1 ∣ + ∣ G 2 ∣ + ∣ G 3 ∣ = n |G_1|+|G_2|+|G_3|=n ∣G1∣+∣G2∣+∣G3∣=n可得:
( 7 / 4 ) ∗ ∣ G 3 ∣ ≤ n ⇒ ∣ G 3 ∣ ≤ ( 4 / 7 ) ∗ n (7/4)*|G_3|\leq n \Rightarrow|G_3|\leq(4/7)*n (7/4)∗∣G3∣≤n⇒∣G3∣≤(4/7)∗n
code:
#include
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a
#define KEEP while(1)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define debug_pair(A) cerr<
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
typedef pair<mp,mp> superpair;
int T;
int n,m;
vector<int> g[200000+2];
bool vis[200000+2];
void solve(){
cin>>n>>m;
rb(i,1,n)
g[i].clear(),vis[i]=0;
rb(i,1,m)
{
int u,v;
cin>>u>>v;
g[v].PB(u);
}
vector<int> res;
rb(i,1,n){
bool ok=0;
for(auto it:g[i]){
if(ok) break;
if(!vis[it])
for(auto it2:g[it]){
if(!vis[it2]){
ok=1;
break;
}
}
}
if(ok){
vis[i]=1;
res.PB(i);
}
// done:;
}
cout<<res.size()<<endl;
for(auto it:res){
cout<<it<<" ";
}
cout<<endl;
}
int main(){
fastio;
cin>>T;
while(T--) {
// cout<<"#\n";
solve();
}
return 0;
}
首先可以发现如果你放了k个后存在一段连续的长度为k的开着的灯,那么这k个灯可以被削掉,这样总数上并没有变。
当然你也不可能故意让对手消掉这么多,换取更优解,毕竟你无法控制对方。
所以上述操作是一次无效操作。
可以获得性质1:
然后就可以发现如果你的策略最终造成的局面不是很"均匀"那么,对方完全可以在密集的地方删除,所以稀疏的地方就浪费了。
可以获得性质2:
所以可以大概想到最终的结果是一段一段长度为k的连续的1,中间空着0(1表示亮着),每次点亮k+1个就ok了,因为每次最多消掉k个。其中k可以枚举。
code:
#include
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a
#define KEEP while(1)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define debug_pair(A) cerr<
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
typedef pair<mp,mp> superpair;
bool on[1002],need[1002];
int n,m;
void query(vector<int> v){
// cerr<<"?";
cout<<v.size()<<" ";
for(auto it: v){
on[it]=1;
cout<<it<<" ";
}
cout<<endl;
ff;
int pos;
cin>>pos;
rb(i,1,v.size()){
on[(pos+i-1)%n ? (pos+i-1)%n:n]=0;
// cout<<((pos+i-1)%n ? (pos+i-1)%n:n)<
}
}
int main(){
fastio;
cin>>n;
if(n<=3){
cout<<0<<endl;
ff;
return 0;
}
int best=-INF;
rb(i,1,n){
rb(j,1,n)
need[j]=0;
for(int j=1,cnt=1;j<=n;j++,cnt++){
if(cnt==i+1){
cnt=0;
continue;
}
need[j]=1;
}
need[n]=0;
int tmp=0;
rb(j,1,n)
tmp+=need[j];
if(tmp>best+i){
best=tmp-i;
m=i;
}
}
// cout<
rb(j,1,n)
need[j]=0;
for(int j=1,cnt=1;j<=n;j++,cnt++){
if(cnt==m+1){
cnt=0;
continue;
}
need[j]=1;
}
need[n]=0;
while(1){
vector<int> que;
rb(i,1,n){
if(need[i]&&!on[i]){
que.PB(i);
if(que.size()==m+1) break;
}
}
// cout<
if(que.size()<=1) break;
query(que);
bool ok=1;
rb(i,1,n){
if(need[i]){
if(i>que[que.size()-1]) ok=0;
}
}
if(ok){
break;
}
}
cout<<0<<endl;
return 0;
}