linkkkk
题意:
构造一个01序列,要求序列里00 , 01 , 10 , 11的个数为给定的数
思路:
如果说该序列有x个0,那么00的个数为x ∗ ( x − 1 ) / 2,可以预处理出这个。对于输入的00 , 11个数,求出c n t 0 , c n t 1分别表示0 , 1的个数
如果无法求出c n t 0 , c n t 1的话说明该序列无法构造。
c n t 0 ∗ c n t 1 = 10 + 01,因为相当于任意选取一个,一定会对这两个有贡献的。
假设现在一定合法,考虑如何构造这个序列。假设序列是00001111这种形式,那么在输出的时候,如果c n t 10 > = c n t 0,应该输出1,因为还应当构造的10个数大于等于剩下的0的个数,如果放0的话,只会更少,无法构造乐就。放了1之后造成的影响为c n t 1 − − ,并且还会构造出c n t 0个10;反之,输出0.
如果只有0 / 1的话,特判一下就行了。
代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=2e5+10,inf=0x3f3f3f3f; map<ll,ll>mp; ll a,b,c,d; int main(){ mp[0]=1; for(ll i=1;i*(i-1)/2<=1e9;i++) mp[i*(i-1)/2]=i; cin>>a>>b>>c>>d; if(!mp[a]||!mp[d]){ puts("Impossible"); return 0; } if(b+c+d==0){ while(mp[a]) cout<<"0",mp[a]--; return 0; } if(a+b+c==0){ while(mp[d]) cout<<"1",mp[d]--; return 0; } ll cnt0=mp[a],cnt1=mp[d]; if(cnt0*cnt1!=b+c){ puts("Impossible"); return 0; } while(cnt0+cnt1){ if(c>=cnt0){ cout<<"1"; c-=cnt0; cnt1--; } else{ cout<<"0"; d-=cnt1; cnt0--; } } return 0; } /* */