Codeforces Global Round 9,掉到了1791
A.Sign Flipping
很简单,正负轮流就好
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 
 | #include<bits/stdc++.h>
 using namespace std;
 typedef long long ll;
 typedef pair<int,int>pii;
 
 const int maxn=105,inf=0x3f3f3f3f,mod=1000000007;
 int a[maxn];
 signed main()
 {
 std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
 #ifdef DEBUG
 freopen("input.in", "r", stdin);
 
 #endif
 int t,n;
 cin>>t;
 while(t--)
 {
 cin>>n;
 for(int i=1;i<=n;i++)
 {
 cin>>a[i];
 if(i&1)
 a[i]=-abs(a[i]);
 else
 a[i]=abs(a[i]);
 }
 for(int i=1;i<=n;i++)
 cout<<a[i]<<' ';
 cout<<endl;
 }
 return 0;
 }
 
 | 
B.Neighbor Grid
还是先判断是否有解,贪心构造
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 
 | #include<bits/stdc++.h>
 using namespace std;
 typedef long long ll;
 typedef pair<int,int>pii;
 
 const int maxn=305,inf=0x3f3f3f3f,mod=1000000007;
 int a[maxn][maxn];
 signed main()
 {
 std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
 #ifdef DEBUG
 freopen("input.in", "r", stdin);
 
 #endif
 int t,n,m;
 cin>>t;
 while(t--)
 {
 cin>>n>>m;
 bool ok=1;
 for(int i=1;i<=n;i++)
 {
 for(int j=1;j<=m;j++)
 {
 cin>>a[i][j];
 if(a[i][j]>4)
 ok=0;
 else if((i==1||i==n)&&(j==1||j==m)&&a[i][j]>2)
 ok=0;
 else if((i==1||i==n||j==1||j==m)&&a[i][j]>3)
 ok=0;
 }
 }
 for(int i=1;i<=n;i++)
 for(int j=1;j<=m;j++)
 {
 if((i==1||i==n)&&(j==1||j==m))
 a[i][j]=2;
 else if(i==1||i==n||j==1||j==m)
 a[i][j]=3;
 else
 a[i][j]=4;
 }
 cout<<(ok?"YES":"NO")<<endl;
 if(ok)
 {
 for(int i=1;i<=n;i++)
 {
 for(int j=1;j<=m;j++)
 cout<<a[i][j]<<' ';
 cout<<endl;
 }
 }
 }
 return 0;
 }
 
 | 
C.Element Extermination
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 
 | #include<bits/stdc++.h>
 using namespace std;
 typedef long long ll;
 typedef pair<int,int>pii;
 
 const int maxn=3e5+10,inf=0x3f3f3f3f,mod=1000000007;
 int a[maxn];
 signed main()
 {
 std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
 #ifdef DEBUG
 freopen("input.in", "r", stdin);
 
 #endif
 int t,n;
 cin>>t;
 while(t--)
 {
 cin>>n;
 for(int i=1;i<=n;i++)
 cin>>a[i];
 cout<<(a[1]<a[n]?"YES":"NO")<<endl;
 }
 return 0;
 }
 
 | 
D.Replace by MEX
题意
给你$n$个范围在$[0,n]$区间内的整数,你可以进行最多$2n$次如下操作,使用数组的$MEX$替换数组的任意一个元素。请输出一种得到非递减序列的方案。
思路
尝试构造$0,1,2\dots n-1$的序列,设下标从$0$开始,每个位置与下标相等的点为确定点,当每个点都为确定点时,构造完毕。只需要将每次得到的$MEX$填入对应的下标,即可得到新的确定点(因为$MEX$一定不在数组中),当得到的$MEX$为$n$时要特判,找到一个不为确定点的元素并替换。
代码
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 
 | #include<bits/stdc++.h>
 using namespace std;
 typedef long long ll;
 typedef pair<int,int>pii;
 
 const int maxn=1005,inf=0x3f3f3f3f,mod=1000000007;
 int n,a[maxn];
 int MEX[maxn];
 int mex()
 {
 for(int i=0;i<=n;i++)
 if(!MEX[i])
 return i;
 }
 signed main()
 {
 std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
 #ifdef DEBUG
 freopen("input.in", "r", stdin);
 
 #endif
 int t;
 cin>>t;
 while(t--)
 {
 cin>>n;
 int fix=0;
 memset(MEX,0,sizeof(MEX));
 for(int i=0;i<n;i++)
 {
 cin>>a[i];
 MEX[a[i]]++;
 if(a[i]==i)
 fix++;
 }
 vector<int>ans;
 while(fix<n)
 {
 int now=mex();
 if(now==n)
 {
 for(int i=0;i<n;i++)
 {
 if(a[i]!=i)
 {
 MEX[a[i]]--;
 MEX[a[i]=now]++;
 ans.push_back(i+1);
 break;
 }
 }
 }
 else{
 MEX[a[now]]--;
 MEX[a[now]=now]++;
 fix++;
 ans.push_back(now+1);
 }
 }
 cout<<ans.size()<<endl;
 for(auto &x:ans)
 cout<<x<<' ';
 cout<<endl;
 }
 return 0;
 }
 
 | 
E.Inversion SwapSort
题意
给你长度为$n$的序列$a$,你要将$a$中所有逆序对的下标对做一个排列形成操作序列,当你按次序交换每一个下标后,$a$是按非递减排好序的。
思路
令$pos[x]=i$表示元素$x$的当前下标为$i$。先考虑对于一个排列$p$该如何操作:第$i$轮将第$i$大的元素移到第$i$位。记在当前第$i$位的元素为$q_i$,因为$[i+1,n]$区间元素已经归位,当前因为$q_i$而形成的逆序对(即逆序对的第二个数值为$i$)为数值$q_i+1,q_i+2,\dots i$与$q_i$构成的逆序对。这时依次交换$(pos[q_i+1],i),(pos[q_i+2],i),\dots,(pos[i],i)$即可使$i$移动到第$i$位且[1,i-1]位每个元素相对大小不变。
PS:依次交换$(pos[q_i+1],i),(pos[q_i+2],i),\dots,(pos[i],i)$相当于从$[q_i,i]$依次用$x-1$替换$x$,并最终将$i$填入$i$,相当于$[1,i-1]$区间的大于$q_i$的部分全部减1,相对大小不变,逆序对也不发生变化。
当数组中出现了数值相等情况时,更改元素的值,令后面的元素大于前面的元素,不影响答案。
代码
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 
 | #include<bits/stdc++.h>
 using namespace std;
 typedef long long ll;
 typedef pair<int,int>pii;
 #define int ll
 const int maxn=1e5+10,inf=0x3f3f3f3f,mod=1000000007;
 struct BinaryIndexedsTree
 {
 int n;
 ll c[maxn],sum[maxn];
 inline int lowbit(int x)
 {
 return x & (-x);
 }
 void build(int *a,int n)
 {
 this->n=n;
 memset(c,0,sizeof(c));
 memset(sum,0,sizeof(sum));
 for(int i=1;i<=n;i++)
 add(i,a[i]-a[i-1]);
 }
 void add(int k,ll val)
 {
 for(int i=k;i<=n;i+=lowbit(i))
 c[i]+=val,sum[i]+=val*(k-1);
 }
 void radd(int l,int r,ll val)
 {
 add(l,val);
 add(r+1,-val);
 }
 ll query(int k)
 {
 ll ret=0;
 for(int i=k;i;i-=lowbit(i))
 ret+=k*c[i]-sum[i];
 return ret;
 }
 } bit;
 int a[maxn],pos[maxn];
 signed main()
 {
 std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
 #ifdef DEBUG
 freopen("input.in", "r", stdin);
 
 #endif
 vector<pii>ans;
 vector<int>v;
 map<int,int>mp;
 int n;
 cin>>n;
 bit.build(a,n);
 for(int i=1;i<=n;i++)
 cin>>a[i],v.push_back(a[i]);
 sort(v.begin(),v.end());
 v.erase(unique(v.begin(),v.end()),v.end());
 for(int i=1;i<=n;i++)
 a[i]=lower_bound(v.begin(),v.end(),a[i])-v.begin()+1;
 for(int i=1;i<=n;i++)
 bit.radd(a[i],a[i],1);
 for(int i=1;i<=n;i++)
 {
 mp[a[i]]++;
 a[i]=bit.query(a[i]-1)+mp[a[i]];
 pos[a[i]]=i;
 }
 for(int i=n;i>=1;i--)
 {
 for(int j=a[i]+1;j<=i;j++)
 {
 int p1=pos[j],p2=i;
 pos[a[p1]]=p2;
 pos[a[p2]]=p1;
 swap(a[p1],a[p2]);
 ans.push_back(make_pair(p1,p2));
 }
 }
 cout<<ans.size()<<endl;
 for(auto &x:ans)
 cout<<x.first<<' '<<x.second<<endl;
 return 0;
 }
 
 | 
F. Integer Game
一道交互题
题意
两个人在玩一个游戏,B有三堆数量不同的石子$a,b,c$,A每次给B石子任意个,B可以将这些石子合并到任意一堆,但不能连续合并到相同一堆。如果其中有两堆石子数量相同,则A胜;若超过1000次A仍未胜出,则B胜出。
思路
可以发现,当三个数构成等差数列且最大堆无法操作时,A必胜。
所以我们尽量创造这种情况,假设$a<b<c$,得到$y$的那一堆会变为最大
- 若B将$y$加在$a$上,解得$y=2c-b-a$
- 若B将$y$加在$b$上,解得$y=2c-b-a$
- 若B选择加在$c$上,则无解
所以我们又要创造前置情况:B无法对最大的堆进行操作,即将第一个$y$设为一个很大的数,任意一堆合并后都会变为最大。
因此,A在三步内必胜
 1.给出一个很大的数
 2.给出$2c-b-a$
 3.给出公差
代码
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 
 | #include<bits/stdc++.h>
 using namespace std;
 typedef long long ll;
 typedef pair<int,int>pii;
 
 const int maxn=2e5+10,inf=0x3f3f3f3f,mod=1000000007;
 signed main()
 {
 std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
 #ifdef DEBUG
 freopen("input.in", "r", stdin);
 
 #endif
 ll pre=1000000000,a[4],x;
 for(int i=1;i<=3;i++)
 cin>>a[i];
 
 cout<<"First"<<endl;
 int cnt=0;
 cout<<pre<<endl;
 cout.flush();
 while(cin>>x&&x)
 {
 a[x]+=pre;
 if(cnt==0)
 pre=3*max({a[1],a[2],a[3]})-a[1]-a[2]-a[3];
 else
 pre=(max({a[1],a[2],a[3]})-min({a[1],a[2],a[3]}))>>1;
 cout<<pre<<endl;
 cout.flush();
 cnt++;
 }
 return 0;
 }
 
 |