Codeforces Round 1071 (Div. 3) A-E
A. Blackslex and Password
让位置 \(1,1+x,1+2x...,1+(k-1)x\) 用完前 \(k\) 个字母,则位置 \(1+kx\) 的字母必定要和前面那几个位置重复,所以答案就是 \(k*x+1\)
B. Blackslex and Showering
可以先计算出删数之前的答案 \(sum\)
然后可以 \(for\) 循环枚举删除第 \(i\) 个数
此时,删除这个数对答案造成的贡献是:\(-abs(a[i]-a[i-1])-abs(a[i]-a[i+1])+abs(a[i-1]-a[i+1])\)
所以此时,\(ans_i=sum-abs(a[i]-a[i-1])-abs(a[i]-a[i+1])+abs(a[i-1]-a[i+1])\)
对 \(ans\) 取最小值即可
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int n,ans=0;
cin>>n;
vector<int> a(n+1);
for(int i=1;i<=n;i++){
cin>>a[i];
if(i!=1) ans+=abs(a[i]-a[i-1]);
}
int x=-inf;
for(int i=1;i<=n;i++){
int val=0;
if(i==n) val=abs(a[i]-a[i-1]);
else if(i==1) val=abs(a[i]-a[i+1]);
else{
val=abs(a[i]-a[i-1])+abs(a[i]-a[i+1])-abs(a[i-1]-a[i+1]);
}
x=max(x,val);
}
// sum-abs(a[i]-a[i-1])-abs(a[i]-a[i+1])+abs(a[i-1]-a[i+1])
cout<<ans-x<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int t=1;
cin>>t;
while(t--){
solve();
}
}
C. Blackslex and Number Theory
先考虑对 \(a\) 数组排序,此时 \(a[1]\) 为最小值,\(a[2]\) 为次小值
考虑让 \(k=a[1]\) 是否成立?显然成立,因为此时 \(a[1]~mod~k=0\),而对于其他的数,也可以选择 \(x=a[i]\),使得 \(a[i]~mod~x=0\)
考虑让 \(k=a[2]\) 是否成立?
不成立,因为此时,\(a[1]~mod~a[2]=a[1]\),但 \(a[2]~mod~k=0\),\(a[2]~mod~x(x>k)=a[2]\)
显然不相等,所以不成立
再考虑 \(k\) 在 \([a[1]+1,a[2]-1]\) 范围内,此时 \(a[1]~mod~k=a[1]\)
要使得 \(a[2]~mod~k=a[1]\),则 \(k\) 最大可以取 \(a[2]-a[1]\)
如果\(a[2]-a[1]>a[1]\) 则 \(k\) 可以取到 \(a[2]-a[1]\),此时其他数,也可以找到一个 \(x=a[i]-a[i]>k\),使得 \(a[i]~mod~x=a[1]\)
否则 \(k\) 最大只能取 \(a[1]\)
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int n;
cin>>n;
vector<int> a(n+1);
for(int i=1;i<=n;i++){
cin>>a[i];
}
sort(a.begin()+1,a.end());
int ans=a[1];
if(a[2]-a[1]>a[1]) ans=a[2]-a[1];
cout<<ans<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int t=1;
cin>>t;
while(t--){
solve();
}
}
D. Blackslex and Penguin Civilization
为了最大化 \(S(p)\),我们需要让前缀的 \(\text{AND}\) 值尽可能大,并且保持尽可能长的时间。
显然,排列的第一个数必须是 \(2^n-1\)(全 \(1\)),这样初始的 \(\text{popcount}\) 才是 \(n\)。
维护一个当前的 \(\text{mask}\)(初始为 \(2^n-1\))。
当我们将 \(\text{mask}\) 的最高位去掉(即变为 \(\text{mask} >> 1\))之前,应该把所有满足 \((x \ \& \ \text{mask}) == \text{mask}\) 且未被使用的数 \(x\) 全部填入。
原因如下:
关于得分:对于满足条件的 \(x\),填入后前缀 \(\text{AND}\) 值依然是 \(\text{mask}\),不会变小,从而“白嫖”了当前的 \(\text{popcount}\) 分数。
关于字典序:我们在枚举满足条件的 \(x\) 时,从小到大枚举即可保证字典序最小。
关于 Mask 变换:为了让靠前的数字尽可能小,我们应当每次去掉 \(\text{mask}\) 的最高位(或者理解为右移),而不是去掉低位。
所以策略是:初始化 \(\text{mask} = 2^n-1\),先输出这个数。然后进行 \(n\) 轮循环,每次将 \(\text{mask}\) 更新为 \(\text{mask} >> 1\)。在每一轮中,从小到大遍历 \(0 \dots 2^n-1\),如果当前数 \(j\) 未被访问且 \((j \ \& \ \text{mask}) == \text{mask}\),则将其加入排列。
(最后一步可以不用遍历 \(0 \dots 2^n-1\) ,可以做优化,但复杂度不变)
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int n;
cin>>n;
int now=n;
vector<bool> a(1<<n,false);
while(now){
int mask=(1<<now)-1;
cout<<mask<<" ";
a[mask]=1;
int t=n-now;
for(int i=0;i<(1<<t)-1;i++){
int val=(i<<now)|mask;
if(!a[val]){
a[val]=1;
cout<<val<<" ";
}
}
now--;
}
for(int i=0;i<(1<<n);i++){
if(!a[i]) cout<<i<<' ';
}
cout<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int t=1;
cin>>t;
while(t--){
solve();
}
}
E. Blackslex and Girls
先构造出一种策略,将 \(p[i]\) 在符合要求的前提下填满,如果填不满或不符合要求,则可以直接输出 NO 了
记此时在区域 \(i\),有 \(a[i]\) 个 \(x\),\(b[i]\) 个 \(y\)
现在,每个位置都填到了 \(p[i]\),假设现在 \(x,y\) 都剩下一些数,则 \(x,y\) 之间可以一一抵消,此时较小数变为零。
假设此时 \(x<y\),所以 \(x=0,y!=0\)
分类讨论:
\(s\) 有 1 有 0,则可以将 \(y\) 分别放进 \(y\) 获胜的区域,结束
\(s\) 只有 1,同上
\(s\) 只有 0,此时,需要把 \(y\) 放到 \(x\) 赢的区域里,对于区域 \(i\),最多可以放: \(a[i]-b[i]-1\) 个 \(y\),才能满足这个区域的 \(x\) 还是大于 \(y\) 的
\(x>y\) 时同理
可以证明,初始的 \(p[i]\) 只要保证符合胜负要求,\(x,y\) 填多填少无所谓,对答案没影响。至于证明过程,这里篇幅太小写不下
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int n,x,y;
cin>>n>>x>>y;
string s;
cin>>s;
s=" "+s;
vector<int> p(n+1);
for(int i=1;i<=n;i++){
cin>>p[i];
}
vector<int> a(n+1),b(n+1);
for(int i=1;i<=n;i++){
if(s[i]=='0'){
int cnt=p[i]/2+1;
if(x>=cnt){
a[i]=cnt;
x-=cnt;
}
else{
cout<<"NO\n";
return;
}
}
else{
int cnt=p[i]/2+1;
if(y>=cnt){
b[i]=cnt;
y-=cnt;
}
else{
cout<<"NO\n";
return;
}
}
}
for(int i=1;i<=n;i++){
if(s[i]=='0'){
//a[i]=p/2+1
if(x>=p[i]-a[i]){
x-=p[i]-a[i];
a[i]=p[i];
}
else{
a[i]+=x;
x=0;
if(y>=p[i]-a[i]){
y-=p[i]-a[i];
b[i]=p[i]-a[i];
}
else{
cout<<"NO\n";
return;
}
}
}
else{
//b[i]=p/2+1
if(y>=p[i]-b[i]){
y-=p[i]-b[i];
b[i]=p[i];
}
else{
b[i]+=y;
y=0;
if(x>=p[i]-b[i]){
x-=p[i]-b[i];
a[i]=p[i]-b[i];
}
else{
cout<<"NO\n";
return;
}
}
}
}
if(x || y){
int t=min(x,y);
x-=t,y-=t;
}
if(x){
for(int i=1;i<=n;i++){
if(s[i]=='0'){
break;
}
else{
// int diff=a[i]-b[i]-1;
int diff=b[i]-a[i]-1;
x-=diff;
if(x<=0) break;
}
if(i==n){
cout<<"NO\n";
return;
}
}
}
if(y){
for(int i=1;i<=n;i++){
if(s[i]=='1'){
break;
}
else{
// int diff=b[i]-a[i]-1;
int diff=a[i]-b[i]-1;
y-=diff;
if(y<=0) break;
}
if(i==n){
cout<<"NO\n";
return;
}
}
}
cout<<"YES\n";
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int t=1;
cin>>t;
while(t--){
solve();
}
}

浙公网安备 33010602011771号