CF Round #850 (Div.2) 解题报告 (A~C)
Codeforces Round 850 (Div.2)
代码不含多测相关内容。
A1. Non-alternating Deck (easy version)
直接模拟发牌过程即可。
ll n,ans,a,b,s,i,j;
void Solve()
{
cin>>n;
a=b=s=0;
for(i=0,j=1;i<n;j++)
{
ll i1=i;
i=min(i+j,n);
if(s%4==0||s%4==3)a+=i-i1;else b+=i-i1;
s++;
}
cout<<a<<" "<<b<<endl;
}
A2. Alternating Deck (hard version)
本来以为 A2 就是增大 \(n\) 的范围
这次,我们考虑一张一张地发牌。直接算出这张牌发给谁,是什么颜色即可。预先打表出答案,每次寻味直接输出。
int f[1000005][4];
int x(int t){return t%4==1||t%4==2;}
void Init()
{
int s=0,t=0;
for(int i=1,nxt=1,j=1;i<=1000000;i++)
{
for(int j=0;j<4;j++)f[i][j]=f[i-1][j];
f[i][s+x(t)*2]++;
s=!s;
if(i==nxt)t++,j++,nxt+=j;
}
}
int n;
void Solve()
{
cin>>n;
for(int i=0;i<4;i++)cout<<f[n][i]<<" ";
cout<<endl;
}
B. Cake Assembly Line
因为只能喷一次,所以第 \(i\) 个蛋糕肯定会被第 \(i\) 个机器喷上巧克力。于是,我们可以算出第 \(i\) 个蛋糕移动到的坐标的范围。易知 \(l_i=b_i-w+h,r_i=b_i+w-h\)。再将其减去 \(a_i\),就可以知道蛋糕移动的范围。于是我们可以算出偏移量的最小值 \(mi\) 与最大值 \(ma\),当且仅当 \(mi\le ma\) 时有解。
const int N=100005;
int n;
ll h,w,a[N],b[N],mi,ma,l[N],r[N];
void Solve()
{
cin>>n>>w>>h;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)cin>>b[i];
mi=INT_MIN,ma=INT_MAX;
for(int i=1;i<=n;i++)
l[i]=b[i]-w+h,r[i]=b[i]+w-h;
for(int i=1;i<=n;i++)
mi=max(mi,a[i]-r[i]),ma=min(ma,a[i]-l[i]);
cout<<(mi<=ma?"YES":"NO")<<endl;
}
C. Monsters (easy version)
显然,要让操作 1 的次数尽量少,就要让操作 2 的效果尽量大。不妨将操作 2 放在最后做一次,然后将怪物全部杀死。
如何使操作 2 的效果尽量大?要让他打出更多的“连击”。也就是说,每削一次至少杀死一只怪物。
也就是说,剩下的怪物里,假设血量剩余最多的怪物血量为 \(x\),那么血量为 \(1\sim x\) 的怪物必须全部有至少一个。
那么解法就出来了:先将 \(a\) 从小到大排序,然后遍历每只怪物,如果和上一只血量接不上,就将他攻到比上一个怪物多 1 滴血。
const int N=200005;
int n,a[N];
ll ans;
void Solve()
{
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
sort(a+1,a+n+1);
ans=0;
for(int i=1,j=1;i<=n;i++)
{
if(a[i]<j)continue;
ans+=a[i]-j;
j++;
}
cout<<ans<<endl;
}