题意: 给一个数组a,确定一个排列b,使得ai-bi所形成的ci中不同的元素的给额数最大
思路:将a数组按照值排序,最小的放n,依次放b,最后按照i排序输出答案
diamond:
#include<bits/stdc++.h>
using namespace std;
#define int long long
bool cmp1(pair<int,int>x,pair<int,int>y){
return x.first<y.first;
}
bool cmp2(pair<int,int>x,pair<int,int>y){
return x.second<y.second;
}
void solve(){
int n;
cin>>n;
vector<pair<int,int>>q;
for (int i = 1; i <=n ; ++i) {
int x;
cin>>x;
q.push_back({x,i});
}
sort(q.begin(),q.end(),cmp1);
for (int i = 0; i <n ; ++i) {
q[i].first=n-i;
}
sort(q.begin(),q.end(),cmp2);
for (auto i:q) {
cout<<i.first<<' ';
}
cout<<endl;
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t;
cin>>t;
while (t--){
solve();
}
}
题意:给一个字符串,你的目的是要把他变成回文串,你有一个操作是将0或1取反,问当操作次数是i次时,是否可以将字符串变为回文串
思路:我们先对非回文的地方进行统计个数cnt,当我们的操作次数>=cnt
diamond:
#include<bits/stdc++.h>
using namespace std;
#define int long long
bool cmp1(pair<int,int>x,pair<int,int>y){
return x.first<y.first;
}
bool cmp2(pair<int,int>x,pair<int,int>y){
return x.second<y.second;
}
void solve(){
int n;
cin>>n;
string s;
cin>>s;
int cnt=0;
for (int i = 0; i <n/2 ; ++i) {
if(s[i]!=s[n-i-1]){
cnt++;
}
}
// cout<<cnt<<endl;
if (n&1) {
for (int i = 0; i <= n; ++i) {
if (i >= cnt && n - i >= cnt) {
cout << "1";
} else {
cout << "0";
}
} cout << '\n';
return;
}
else {
int vis=0;
for (int i = 0; i <= n; ++i) {
if (i >= cnt && n - i >= cnt) {
if(vis&1)cout<<'0';
else cout<<'1';
vis++;
} else {
cout << "0";
}
}
cout << '\n';
return;
}
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t;
cin>>t;
while (t--){
solve();
}
}
题意:交互题,Alice和Bob游戏,刚开始是有n个数字,Alice是加入数字,Bob要删除数字,Alice是要MEX最大化,而Bob要MEX最小化,问游戏结束时或者进行了2 * n+1次时,MEX是多大,游戏结束时输出-1,你要做Alice,Bob是机器,你选择加入一个数字,他选择删除一个数字
思路:因为两者都有优先选择的方法,那么其实答案只能是原数字的MEX值+1,我们加入就是加这个数,他删也是只能删除这个数字,最后-1结束
diamond:
#include<bits/stdc++.h>
using namespace std;
#define int long long
void solve(){
int n;
cin>>n;
set<int>st;
for (int i = 0; i <n ; ++i) {
int x;
cin>>x;
st.insert(x);
}
int vis=0;
int mex=0;
int biaozhi;
for (int i = 0; i <=n ; ++i) {
if(st.count(i)==1){
mex++;
}
else{
if(vis==0){
biaozhi=i;
mex++;
vis=1;
}
else{
break;
}
}
}
cout<<biaozhi<<endl;
int x;
for (int i = 0; i <n ; ++i) {
cin>>x;
if(x==-1){
return;
}
// if(x==-2)exit(0);
cout<<x<<endl;
}
cin>>x;
return;
// cout<<mex<<endl;
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t;
cin>>t;
while (t--){
solve();
}
}
题意:给定一个长度位n的数组b,和一个数字k,同时有一个a数组,起初a数组为0,你可以进行无数次操作,构造出一个长度为k的数组L,令aLi=L(i%k+1);问是否可以使得a与b相等呢
思路:给定的表达式,可以想到环的内容,类似 2 4 3 1,2 4 1 是一个内部的环,2->4,4->1,1->2这样建边,然后然后对3,不是一个环,那么就可以先借用他连通的环,先修改当前的数,然后再修改环内的数,因此直接拓扑序求一下环的大小即可,环的大小必须是k,如果k=1时,那么任何数字都是一个自环才可以
diamond:
#include<bits/stdc++.h>
using namespace std;
//#define int long long
void solve()
{
int n,k;
cin>>n>>k;
vector<int>g(n+1);
vector<int >d(n+1);
vector<int >a(n+1);
for (int i = 1; i <=n ; ++i) {
cin>>a[i];
}
for (int i = 1; i <=n ; ++i) {
g[a[i]]=a[a[i]];
}
for (int i = 1; i <=n ; ++i) {
d[g[i]]++;
}
if(k==1)
for (int i = 1; i <=n ; ++i){
if(i!=g[i]){
cout<<"NO\n";
return;
}
}
queue<int>q;
for (int i = 1; i <=n ; ++i) {
if(!d[i]){
q.push(i);
}
}
while (!q.empty()){
auto t=q.front();
q.pop();
d[g[t]]--;
if(!d[g[t]]){
q.push(g[t]);
}
}
for (int i = 1; i <=n ; ++i) {
if(d[i]){
int cnt=1;
int dq=i;
d[i]--;
while (1){
if(d[g[dq]]){
cnt++;
d[g[dq]]--;
}
else break;
dq=g[dq];
}
if(cnt!=k){
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();
}
}
题意:交互题,给一个n和k,你的目的是得到数组大小为n的数组a的异或和,每次你可以询问一个位置i,会返回给你这个数组从i到i+k-1的异或和,并且将这些数的相对位置颠倒,你必须在不超过100次的询问之中得到答案,假设我们的$n%k==0$时,我们可以直接进行询问,记录异或和即可,例如n=6,k=2,我们询问1,3,5;但当n=8,k=6时,我们这样询问一次,1 2 3 4 5 6 7 8,我们询问第一次 1,得到1 2 3 4 5 6的异或和,然后得到6 5 4 3 2 1 7 8,然后我们考虑如何得到 7 8,我们可以这样询问,首先询问 2,得到 5 4 3 2 1 7的异或和,然后变成 6 7 1 2 3 4 5 8,然后我们再询问3 ,得到 1 2 3 4 5 8,变成 5 6 7 4 3 2 1 8,然后就可以得到了 7 8的异或和了,期间的1 2 3 4 5异或了偶数次,被抵消,这样即可在100次以内拿下
diamond:
#include<bits/stdc++.h>
using namespace std;
#define int long long
void solve()
{
int n,k;
cin>>n>>k;
int ans=0;
int x;
for (int i = 1; i <=n-k+1; i+=k) {
cout<<"? "<<i<<endl;
cin>>x;
ans^=x;
}
if(n%k==0){
cout<<"! "<<ans<<endl;
return;
}
else{
int g=n/k;
g--;
for (int i = 2+g*k; i <=2+g*k+n%k-1 ; ++i) {
cout<<"? "<<i<<endl;
cin>>x;
ans^=x;
}
cout<<"! "<<ans<<endl;
return;
}
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t=1;
cin>>t;
while (t--){
solve();
}
}
题意:与上题一样,只不过100次变为50次
思路:前面不变,但后面可以这样考虑,n=8,k=6,首先对1 进行操作,1 2 3 4 5 6 7 8,得到6 5 4 3 2 1 7 8,然后我们这样操作,对3操作,得到的异或和,然后变成6 5 7 1 2 3 4 8 ,得到7 1 2 3 4 的异或和,然后对4进行操作,得到 1 2 3 4 8的异或和,得出答案,即对n-k-g/2+1操作,和对n-k-1操作,g为n%k
diamond:
#include<bits/stdc++.h>
using namespace std;
#define int long long
void solve()
{
int n,k;
cin>>n>>k;
int ans=0;
int x;
for (int i = 1; i <=n-k+1; i+=k) {
cout<<"? "<<i<<endl;
cin>>x;
ans^=x;
}
if(n%k==0){
cout<<"! "<<ans<<endl;
return;
}
else{
int g=n%k;
cout<<"? "<<n-k-g/2+1<<endl;
cin>>x;
ans^=x;
cout<<"? "<<n-k+1<<endl;
cin>>x;
ans^=x;
cout<<"! "<<ans<<endl;
return;
}
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t=1;
cin>>t;
while (t--){
solve();
}
}