Codeforces Round 1058 (Div. 2) (4/8)
又是一场speedforces ,可恶的棒子。但是好在b题卡了一会后,c,d 都切的很快。把前两场的分上回来了。
A: 分组不影响 mex 的值,所以直接求解 mex 输出即可
B: f(i) 本质是每个后缀,不同数字的个数。可以观察到每增加一个与之前的数字不同的数,贡献是i,所以如果贡献j不足i,说明num[i]=num[i-j]。因为数据保证一定有合法生成,所以不用考虑不存在的情况。
所以对于给定的数组a。
num[i]=num[i-j] ,a[i]-a[i-1]!=i
num[i]=i ,a[i]-a[i-1]==i
inline void solve()
{
int n;
cin>>n;
vector<int> a(n+1);
for(int i=0;i<n;i++)
{
cin>>a[i];
}
vector<int> num(n+1);
num[0]=1;
for(int i=1;i<n;i++)
{
int d=a[i]-a[i-1];
if(d==i+1)
{
num[i]=i+1;
}
else
{
num[i]=num[i-d];
}
}
for(int i=0;i<n;i++) cout<<num[i]<<" ";
cout<<endl;
}
C: 经过一系列观察,发现可以的情况为,数字是一个二进制回文数字(如果长度为奇数,那么中间位不能是1)。但是你可以通过在数字前面补前导0来构成回文。因为数据范围 \(<2^{30}\) 所以最多在数字前面加30次前导0,其中有任意一次符合条件, 即为"YES" ,否则为"NO" 。
inline bool check(string s)
{
if(s.size()%2)
{
if(s[s.size()/2]=='1') return 0;
}
for(int i=0;i<s.size()/2;i++)
{
if(s[i]!=s[s.size()-1-i]) return 0;
}
return 1;
}
inline void solve()
{
int n;
cin>>n;
if(n==0)
{
cout<<"YEs"<<endl;
return;
}
string s;
while(n)
{
s+='0'+(n&1);
n>>=1;
}
for(int i=0;i<=30;i++)
{
string st=s;
for(int j=1;j<=i;j++) st+='0';
if(check(st))
{
cout<<"YEs"<<endl;
return;
}
}
cout<<"NO"<<endl;
}
D: 很简单的一道交互?
按顺序依次将编号放入 查询数组中,如果查询结果为0,则继续;否则该位即为,查询所得的数字,并将该位弹出。遍历第一遍,一定可以找出1-n的数字各一个。第二步,清空查询数组,把找出来的1-n个数字放入查询数组,对于每一个未知位,放入查询数组,查询一次后弹出。第二遍遍历,即可确定未知的n个数字。
int ask(vector<int> a)
{
cout<<"? ";
cout<<a.size()<<" ";
for(int i=0;i<a.size();i++) cout<<a[i]<<" ";
cout<<endl;
int ans;
cin>>ans;
return ans;
}
inline void solve()
{
int n;
cin>>n;
vector<int> ans(2*n+5);
vector<int> a;
a.push_back(1);
int sum=0;
for(int i=2;i<=2*n;i++)
{
a.push_back(i);
int t=ask(a);
if(t==0) continue;
ans[i]=t;
a.pop_back();
sum++;
if(sum==n) break;
}
a.clear();
for(int i=1;i<=2*n;i++)
{
if(ans[i]!=0) a.push_back(i);
}
for(int i=1;i<=2*n;i++)
{
if(ans[i]==0)
{
a.push_back(i);
ans[i]=ask(a);
a.pop_back();
}
}
cout<<"! ";
for(int i=1;i<=2*n;i++)
{
cout<<ans[i]<<" ";
}
cout<<endl;
}

浙公网安备 33010602011771号