原题链接:Dashboard - Codeforces Round 888 (Div. 3) - Codeforces
目录
A. Escalator Conversations
B. Parity Sort
C. Tiles Comeback
D. Prefix Permutation Sums
E. Nastya and Potions
F. Lisa and the Martians
A. Escalator Conversations
题意:
思路:暴力枚举楼梯可以造成的所有差值,然后判断即可。注意楼梯造成的差值最小为k,最大为(m-1)*k。
代码:
void solve() {
int n,m,k,h,ans=0;
cin>>n>>m>>k>>h;
for(int i=1; i<=n; i++) {
int x;
cin>>x;
for(int j=1; j<m; j++) {
if(x-j*k==h||x+j*k==h) {
ans++;
break;
}
}
}
cout<<ans<<endl;
}
B. Parity Sort
题意:
思路:因为奇数元素的位置只能由奇数元素换过来,所以若能有序的话,排完序之后原本奇数位置上还是奇数,偶数位置上还是偶数。
代码:
void solve() {
int n;
cin>>n;
for(int i=1; i<=n; i++) {
cin>>a[i];
b[i]=a[i];
}
sort(a+1,a+n+1);
for(int i=1; i<=n; i++) {
if(a[i]%2!=b[i]%2) {
no;
return;
}
}
yes;
}
C. Tiles Comeback
题意:
思路:只要有k个元素和第一个元素颜色相同,并且有k个元素和最后一个元素颜色相同 ,并且选择这两种颜色的区间不相交,答案即为YES。特别的是,第一个元素和最后一个元素颜色相同,此时只需要k个颜色即可。
代码:
void solve() {
PII l,r;
int n,k;
cin>>n>>k;
for(int i=1; i<=n; i++) {
cin>>a[i];
if(a[i]==a[1]&&l.second!=k)l.first=i,l.second++;
}
for(int i=n; i>=1; i--) {
if(a[i]==a[n]&&r.second!=k)r.first=i,r.second++;
}
if(l.second!=k||r.second!=k) {
no;
return;
}
if(a[1]==a[n]) yes;
else {
if(l.first<r.first)yes;
else no;
}
}
D. Prefix Permutation Sums
题意:
思路:求出该数组的差值后,只有两种情况是YES:
①1~n之间恰好有两个数的位置上是空的,并且恰好有一个数多余的数,等于这两个位置加起来,这样就能使得1~n填满。
②1~n之间恰好有一个数的位置上是空的。此时只需将这缺的数放到数组最后面,就能令数组合法。
void solve() {
unordered_map<int,int>mp;
int n,sum=0,cnt=0,now;
cin>>n;
for(int i=1; i<n; i++) {
cin>>a[i];
mp[a[i]-a[i-1]]++;
}
for(int i=1; i<=n; i++) {
if(!mp[i]) {
cnt++;
sum+=i;
}
}
for(auto x:mp) {
if(x.second>=2||x.first>n) {
now=x.first;
break;
}
}
if(now==sum&&cnt==2||cnt==1)yes;
else no;
}
E. Nastya and Potions
题意:
思路: dfs即可,第i个药水的最小价值为dfs(e[1])+dfs(e[2])+......dfs(e[m[i]))。
代码:
int dfs(int u){
if(st[u]!=-1)return st[u];
if(e[u].size()==0) return c[u];
int sum=0;
for(auto x:e[u]){
sum+=dfs(x);
}
return st[u]=min(c[u],sum);
}
void solve() {
int n,k;
cin>>n>>k;
for(int i=1;i<=n;i++)cin>>c[i],e[i].clear(),st[i]=-1;
for(int i=1;i<=k;i++){
int x;
cin>>x;
c[x]=0;
}
for(int i=1;i<=n;i++){
int x;
cin>>x;
for(int j=1;j<=x;j++){
int xx;
cin>>xx;
e[i].push_back(xx);
}
}
for(int i=1;i<=n;i++)cout<<dfs(i)<<" \n"[i==n];
}
F. Lisa and the Martians
题意:
思路:因为&和^操作对位与位之间不会产生影响,所以我们从单个的位来思考:若两个位不同,那么无论选择的x是什么,这个位异或x然后相与之后都会变成0。
比如第一个数是0,第二个数是1,用1来异或这两数后,第一个数变0,第二个数变1,他们两相与为0;用0来异或这两数后,第一个数还是0,第二个数还是1,他们两相与还是为0。
若两个位相同,我们则可以选择一个与该位相反的数,使这个位异或相与之后为1。
比如第一个数是0,第二个数是0,用1来异或这两数后,第一个数变1,第二个数变1,他们两相与为1;比如第一个数是1,第二个数是1,用0来异或这两数后,第一个数还是1,第二个数还是1,他们两相与还是1;
所以我们需要找到该数组的最大与或对,也就是最小异或对。
然后有一个结论:最小异或对是数组排完序之后,相邻异或和的最小值。
因此我们只需排一下序,然后遍历标记数组,就可以得到最小异或对的位置了。而x的值,可以由这个两个异或对中的任意一个,在二进制位上取反来获得。
代码:
void solve() {
vector<PII>v;
int n,k;
cin>>n>>k;
for(int i=1; i<=n; i++) {
int x;
cin>>x;
v.push_back({x,i});
}
sort(v.begin(),v.end());
int minn=inf,pos1,pos2,ans;
for(int i=1; i<v.size(); i++) {
int x=(v[i].first^v[i-1].first);
if(x<minn) {
minn=x;
pos1=v[i].second,pos2=v[i-1].second,ans=v[i].first;
}
}
cout<<pos1<<" "<<pos2<<" "<<((1<<k)-1-ans)<<endl;
}