Codeforces Round #469 (Div. 1 A-E)
Posted issue是fw
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #469 (Div. 1 A-E)相关的知识,希望对你有一定的参考价值。
A - Zebras
考虑一个子序列必定是以 0 0 0开头,后面跟着若干个 10 10 10
然后考虑当前 a i = 1 a_i=1 ai=1,暂时存下来,等下一个遇到的 0 0 0去匹配
若 a i = 0 a_i=0 ai=0,如果之前有 1 1 1未被匹配,就匹配上去,然后接在刚好能接的某个子序列的后面
如果之前的 1 1 1都被匹配了,只能以这个 0 0 0开头新加一个子序列
#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e5+10;
char a[maxn];
vector<int>vec[maxn];
int n,q[maxn],top,now,id;
set<pair<int,int> >s;
int main()
{
cin >> ( a+1 ); n = strlen( a+1 );
if( a[1]=='1' ){ cout << "-1"; return 0; }
vec[++id].push_back( 1 ); s.insert( {1,id} );
for(int i=2;i<=n;i++)
{
if( a[i]=='1' ) q[++top] = i;
else
{
if( now<top )//之前的1还没有被抵消
{
auto pi = s.lower_bound( { q[++now],0 } );
if( pi==s.begin() ){ cout << -1; return 0; }
pi--;
pair<int,int>v = (*pi);
vec[v.second].push_back( q[now] );
vec[v.second].push_back( i );
s.insert( { i,v.second } ); s.erase( pi );
}
else//新开一个子序列
vec[++id].push_back( i ), s.insert( { i,id } );
}
}
if( now!=top ) { cout << -1; return 0; }
cout << id << endl;
for(int i=1;i<=id;i++)
{
cout << vec[i].size();
for(auto v:vec[i] ) cout << " " << v;
cout << endl;
}
}
B. A Leapfrog in the Array
题意
n n n个数字,数字 i i i落在第 2 ∗ i + 1 2*i+1 2∗i+1个格子的位置
每次操作会把当前最后一个数字移动到它左边第一个空格子处,重复操作直到 [ 1 , n ] [1,n] [1,n]的格子内都有数字
现在有 q q q次询问,每次问第 k k k个格子中是什么数字
n < = 1 0 18 , q < = 2 ∗ 1 0 5 n<=10^{18},q<=2*10^5 n<=1018,q<=2∗105
对于一个数 x x x,后面有 n − x n-x n−x个数字,那么第一次移动会往左
( n − x ) ∗ 2 + 1 (n-x)*2+1 (n−x)∗2+1
然后考虑这个数字 x x x上一次往左走了 k k k步
说明直到下次 x x x位移,右边共有 k − 1 k-1 k−1个数往左占据 k − 1 k-1 k−1个空位
所以自己只能占据左边的第 k k k个空位,那么下次的位移量就是 2 ∗ k 2*k 2∗k
可以看到每次的位移量都是倍增的,设数字 k k k共位移 q q q次,最终到达 x x x位置,有
( 2 ∗ k − 1 ) − x = [ ( n − k ) ∗ 2 + 1 ] ∗ ( 2 q − 1 ) (2*k-1)-x=[(n-k)*2+1]*(2^q-1) (2∗k−1)−x=[(n−k)∗2+1]∗(2q−1)
化简下 2 ∗ n − x = [ ( n − k ) ∗ 2 + 1 ] ∗ 2 q 2*n-x=[(n-k)*2+1]*2^q 2∗n−x=[(n−k)∗2+1]∗2q
( n − k ) ∗ 2 + 1 = 2 ∗ n − x 2 q (n-k)*2+1=\\frac{2*n-x}{2^q} (n−k)∗2+1=2q2∗n−x
观察右边式子的含义,其中 q q q一定是取到最大的,且需要满足整除关系
相当于抹掉 2 ∗ n − x 2*n-x 2∗n−x的低位所有零,实现上可以使用 l o w b i t ( 2 ∗ n − x ) lowbit(2*n-x) lowbit(2∗n−x)得到最低位除一下就好了
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 3e5+10;
int t,n,x;
int lowbit(int x){ return x&(-x); }
signed main()
{
cin >> n >> t;
while( t-- )
{
cin >> x;
int right = ( 2*n-x )/ lowbit(2*n-x);
cout << -( ( right-1 )/2-n ) << endl;
}
}
C.Data Center Maintenance
题意
某土豪公司建立了n个数据中心,把m份资料每份在其中的两个数据中心备份。
每个数据中心在一天h个小时当中有一个小时需要维护,此时不提供资料下载服务。
现在土豪公司想要将其中若干个数据中心的维护时间向后推迟一小时,并要求一天中任意时刻每份资料都可以被下载,问最少选取多少个数据中心维护。
就是不允许两个数据中心的维护时间相同
一张无向图,满足相邻节点的值不相同
现在要使至少一个点的值加一,问至少选择几个点能满足条件
D.Curfew
如果一个宿舍不能有大于等于 b b b个人,那我们干脆让它一个人都没有
这样多余的人可以去填补后面的宿舍
这样一来,满足条件的宿舍都会集中在中间的部分比较优秀
我们就可以二分一个 f f f表示让两端长 f f f的宿舍一个人都没有,判断中间部分是否都能大于等于 b b b人即可
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 3e5+10;
int n,d,b,a[maxn],c[maxn];
bool isok(int f)
{
int dis = d*f, p0 = 1, p1 = n, z = (n+1)>>1;
for(int i=f+1;i<=z;i++)
{
dis += d;
int s = b;
while( a[p0]<s ) s -= a[p0++];
a[p0] -= s;
if( p0-i>dis ) return 0;
if( i==z && (n&1) ) break;
s = b;
while( a[p1]<s ) s -= a[p1--];
a[p1] -= s;
if( (n-i+1)-p1>dis ) return 0;
}
return 1;
}
signed main()
{
cin >> n >> d >> b;
for(int i=1;i<=n;i++) cin >> a[i], c[i] = a[i];
int l = 0, r = n+1, ans = 0;
while( r>=l )
{
int mid = l+r>>1;
memcpy( a,c,sizeof c );
if( isok(mid) ) ans = mid, r = mid-1;
else l = mid+1;
}
cout << ans;
}
E.Binary Cards
考虑 2 a 2^a 2a最多被选择一次.如果选择两次 2 a , 2 a 2^a,2^a 2a,2a,明显是不如选 2 a , 2 a + 1 2^a,2^{a+1} 2a,2以上是关于Codeforces Round #469 (Div. 1 A-E)的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces Round #469 (Div. 2)
Codeforces Round #469 (Div. 1 A-E)
Codeforces Round #436 E. Fire(背包dp+输出路径)