A. Make It Zero
题意:给定一个数组a,你要将所有元素都变为0,你有这样一个操作,选择L,R,将$i∈[l,r]$中的ai所有元素都变为L到R的ai的异或和,最多操作8次,问一个符合条件的操作流程是什么
思路:当是偶数时,我们可以选择L=1,R=N,操作两次即可,当是偶数时,我们先操作1到N-1,然后再操作最后一个数字即可
diamond:
#include<bits/stdc++.h>
using namespace std;
#define int long long
void solve(){
int n;
cin>>n;
vector<int>q(n+1);
int g=0;
for (int i = 1; i <=n ; ++i) {
cin>>q[i];
g^=q[i];
}
vector<pair<int,int>>ans;
if(n&1){
ans.push_back({1,n-1});
ans.push_back({1,n-1});
ans.push_back({n-1,n});
ans.push_back({n-1,n});
}
else{
ans.push_back({1,n});
ans.push_back({1,n});
}
cout<<ans.size()<<endl;
for (auto i:ans) {
cout<<i.first<<' '<<i.second<<endl;
}
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t;
cin>>t;
while (t--){
solve();
}
}
B. 2D Traveling
题意:有n个城市,编号从1到n,前k个城市是主要城市,坐标为$(xi,yi)$;你从x到y城市,如果x和y城市都是主要城市,那么无需成本,其他情况下,费用是x到y的曼哈顿距离,问从起点城市st到终点城市ed,最少花费是多少
思路:我们只需找出st到主要城市的最小值和ed到主要城市的最小值,然后这两个值相加与st到ed的曼哈顿距离取最小即可
diamond:
#include<bits/stdc++.h>
using namespace std;
#define int long long
void solve(){
int n,k,a,b;
cin>>n>>k>>a>>b;
vector<pair<int,int>>q(n+1);
for (int i =1; i <=n ; ++i) {
cin>>q[i].first>>q[i].second;
}
auto [x,y]=q[a];
auto [xx,yy]=q[b];
int ans=abs(x-xx)+abs(y-yy);
int s1=1e18;
int s2=1e18;
for (int i = 1; i <=k ; ++i) {
s1=min(s1,abs(x-q[i].first)+abs(y-q[i].second));
s2=min(s2,abs(xx-q[i].first)+abs(yy-q[i].second));
}
ans=min(s1+s2,ans);
cout<<ans<<endl;
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t;
cin>>t;
while (t--){
solve();
}
}
C. Fill in the Matrix
题意:给两个数n和m,要求构造一个n * m的矩阵,要求每一行都是一个排列,且每一列的MEX构成的数组S,要求MEX(s)最大。
思路:构造题.
不难发现发现当n<m时,MEX最大就是n+1,我们可以考虑这样构造,假设n=3,m=5
- 0 1 2 3 4
- 1 2 3 4 0
- 2 3 4 0 1
那么我们得到的S就是3 0 0 1 2,答案就是4
当n>=m时,由于数字只有0到m-1,那么答案最大也就是m,考虑这样构造,假设n=6,m=5,第二行从a[2]开始
- 0 1 2 3 4
- 2 3 4 0 1
- 3 4 0 1 2
- 4 0 1 2 3
- 0 1 2 3 4
-
0 1 2 3 4
得到的S 为1 2 3 4 0 ,得到的答案就是5
diamond:
#include<bits/stdc++.h> using namespace std; #define int long long #define endl '\n' void solve(){ int n,m; cin>>n>>m; if(m==1){ cout<<0<<'\n'; for (int i = 0; i < n; ++i) { cout<<0<<'\n'; } return; } if(n>=m){ cout<<m<<endl; } else { cout<<n+1<<endl; } vector<int>res; for (int i = 0; i <m ; ++i) { res.push_back(i); } int g=res.size(); for (int i = 0; i <m ; ++i) { res.push_back(i); cout<<res[i]<<' '; } cout<<endl; int qd=2; if(n<m)qd=1; n--; while (n--){ if(qd>=m){ for (int i = 0; i <m ; ++i) { cout<<i<<' '; } cout<<endl; } else { for (int i = qd; i <qd+m ; ++i) { cout<<res[i]<<' '; } cout<<endl; qd++; } } } signed main(){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); int t; cin>>t; while (t--){ solve(); } }
D1. Candy Party (Easy Version)
题意:给一个n个数的数组a,要求令每一个数减去$2^x$,然后加上一个$2^x$,最后是否可以让所有数字都相同
思路1:易知$sum%n!=0$就是NO,我们对每一个数字进行枚举他需要什么和减去什么,32 * 32的复杂度,我们最后判断加的数组和减的数组是否相等就可以了,如果没有任何组合可以得到平均值,那么是NO
diamond1:
#include<bits/stdc++.h> using namespace std; #define int long long #define endl '\n' int cifang[33]; set<int>st; void solve() { int n; cin >> n; vector<int> zeng(32); vector<int> jian(32); vector<int> a(n); int sum = 0; for (int i = 0; i < n; ++i) { cin >> a[i]; sum += a[i]; } if (sum % n) { cout << "No\n"; return; } vector<int> d1(100), d2(100); int vis = 1; for (int i = 0; i < n; ++i) { vis = 1; for (int j = 0; j < 32; ++j) { for (int k = 0; k < 32; ++k) { if (a[i] - (1ll << j) + (1ll << k) == sum / n) { // cout<<sum/n<<endl; // cout<<a[i]<<' '<<(1ll << j)<<' '<<(1ll << k)<<endl; d1[j]++; d2[k]++; vis = 0; break; } } } if (vis == 1) { cout << "NO\n"; return; } } if (d1 == d2) { cout << "YES\n"; } else { cout << "NO\n"; } } signed main(){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); int t; cin>>t; while (t--){ solve(); } }
思路2:我们可以对ai与平均值的差值进行分析,假设我们的差值的绝对值是01111,那么这两次操作就可以是10000-00001,只有这种1是连续的情况和没有1的情况才可以通过两次操作得到答案,高位1的前一位,和最低位的1,这是唯一做法,那么我们可以维护每一个值的差,当是0的时候也没关系,因为他可以当一个中转站,可以忽略,然后如果大于0,那么我们给一个高位1的前一位的1,然后拿走一个最低位的1,如果小于0,则反过来即可。最后判断每一个1是否都是0
diamond2:
#include<bits/stdc++.h> using namespace std; #define int long long void solve() { int n; cin >> n; map<int, int> mp; vector<int >a(n); int ss=0; for (int i = 0; i <n ; ++i) { cin>>a[i]; ss+=a[i]; } if(ss%n) { cout<<"NO\n"; return; } int v=ss/n; for (int i = 0; i <n ; ++i) { int cha=abs(a[i]-v); if(cha==0)continue; string s=bitset<32>(cha).to_string(); int l=-1, r = -1; std::reverse(s.begin(), s.end()); for (int j = 0; j <32 ; ++j) { if(s[j]=='1'){ l=j; break; } } for (int j = 31; j>=0 ; --j) { if(s[j]=='1'){ r=j; break; } } for (int j = l; j <=r ; ++j) { if(s[j]=='0'){ cout<<"NO\n"; return; } } if(a[i]>v){ mp[r+1]++; mp[l]--; } else{ mp[r+1]--; mp[l]++; } } for (auto i:mp) { if(i.second!=0){ cout<<"NO\n"; return; break; } } cout<<"YES\n"; } signed main(){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); int t=1; cin>>t; while (t--){ solve(); } }
D2. Candy Party (Hard Version)
题意:相比与简单版本的,他的变化是一个人可以只给一次,也可以只要一次,也可以给要都1次
思路:我们D2和D1的做法2是同源的,我们发现这个限制,只在差值中只有一个1的时候,才出现了变化,其他情况不变,假设差值是010,原来我们是要1个100,然后给一个010,现在,我们可以只要一个010,我们可以打上标记,标记为我们可以拿两个010去换一个100,意思就是原版本我们的mp[4]--,mp[2]++,我们现在可以描述位mp[2]--,相比就是减去了两个mp[2];当我们访问到2给出了很多次,那么给出两次2,相当于要一个4,就是我们可以把2的值消掉,4的值加回来,对于每一个$2^x$,他只能和$2^x+1$次方进行交换,假设我们遍历到第2位的个数并不是0,那么我们就考虑能否把这个2的个数换位4的个数,假设我们还要得到2个2,那么我们就需要拿走一个4,必须从单个1那边来换,假设还要得到4个2,我们只需两个单1的2,就变为了0,然后得到2个4,4的个数就要+=2,然后继续判断4,如果不够则NO,反之同理
diamond:
#include<bits/stdc++.h> using namespace std; #define int long long void solve() { int n; cin >> n; map<int, int> mp; vector<int >a(n); map<int,int>dedao,shanqu; int ss=0; for (int i = 0; i <n ; ++i) { cin>>a[i]; ss+=a[i]; } if(ss%n) { cout<<"NO\n"; return; } int v=ss/n; for (int i = 0; i <n ; ++i) { int cha=abs(a[i]-v); if(cha==0)continue; string s=bitset<32>(cha).to_string(); int l=-1, r = -1; std::reverse(s.begin(), s.end()); for (int j = 0; j <32 ; ++j) { if(s[j]=='1'){ l=j; break; } } for (int j = 31; j>=0 ; --j) { if(s[j]=='1'){ r=j; break; } } for (int j = l; j <=r ; ++j) { if(s[j]=='0'){ cout<<"NO\n"; return; } } if(a[i]>v){ mp[r+1]++; mp[l]--; if(r==l){ dedao[l]++; } } else{ mp[r+1]--; mp[l]++; if(r==l){ shanqu[l]++; } } } for (auto [x,y]:mp) { if(y!=0){ if(y<0){ y=abs(y); if(y%2==0){ int c=y/2; if(c>abs(dedao[x])){ cout<<"NO\n"; return; } else{ mp[x+1]-=c; } } else{ cout<<"NO\n"; return; } } else{ y=abs(y); if(y%2==0){ int c=y/2; if(c>abs(shanqu[x])){ cout<<"NO\n"; return; } else{ mp[x+1]+=c; } } else{ cout<<"NO\n"; return; } } } } cout<<"YES\n"; } signed main(){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); int t=1; cin>>t; while (t--){ solve(); } }