A.Specific Tastes of Andre
题意:要求输出一个长为n的序列,要求每个非空子数组的权值和能被长度整除。
题解:输出n个1即可。
#include<bits/stdc++.h> using namespace std; int main() { int T; cin>>T; while(T--) { int n; cin>>n; for(int i=0;i<n;i++) printf("1 "); puts(""); } return 0; }
B.Valerii Against Everyone
题意:要求从一个长为n的数组中选出两部分数,使他们对应的权值相同。
题解:如果存在两个相同的数就合法。
#include<bits/stdc++.h> using namespace std; map<int,int>ma; int main() { int T; cin>>T; while(T--) { ma.clear(); int f=0; int n; cin>>n; for(int i=0;i<n;i++) { int x; scanf("%d",&x); if(ma.count(x)!=0)f=1; ma[x]++; } if(f)puts("YES"); else puts("NO"); } }
C.Engineer Artem
题意:给定一个矩阵,要求修改矩阵的值,只能将原矩阵中的值加一或者保持不变,使得到的矩阵没有相邻的格子的值相同。
题解:可以发现:对于一个格子,其相邻的四个方向的格子的横纵坐标之和的奇偶性不同,因此我们可以让每个格子的值的奇偶性与其横纵坐标之和的奇偶性相同,这样,相邻格子的奇偶性不同,值就不可能相等了。
#include<bits/stdc++.h> using namespace std; const int N=110; int a[N][N],b[N][N]; int dx[]={-1,1,0,0}; int dy[]={0,0,1,-1}; int main() { //freopen("1.txt","r",stdin); int n,m; int T; cin>>T; while(T--) { //puts("666"); cin>>n>>m; memset(b,0,sizeof b); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cin>>a[i][j]; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if((i+j)%2!=a[i][j]%2) a[i][j]++; printf("%d ",a[i][j]); } puts(""); } } }
D.Powerful Ksenia
题意:给定一个长为n的数组,可以进行的操作:选择数组的三个数,将他们替换为他们三个的异或值,问是否在n次操作内将原数组所有的数变成相同,
题解:对于三个数的异或a a b最终的值为b,因此我们可以考虑将原数组变成两两相同的的数,最后选择一个数与这些两两相同的数异或即可将所有数都变成相等的。
因此有以下策略:选择1 2 3异或,3 4 5异或.......,最后我们会得到前面两两相同的数,后面剩下三个相同的数,如果是偶数,后面还有一个单独的数。
可以发现如果数组的长度为奇数,那一定可以通过以上策略操作n-2次一定可以构造合法解。
如果数组的长度为偶数,可以发现以上策略最后三组相同的数的值为:a1^a1^...^an-1,如果最后一个数an与a1^a1^...^an-1相同即原数组异或值为0,那么最后四个数相等,可以通过上述策略构造一组解。
#include<bits/stdc++.h> using namespace std; const int N=1e5+100; int a[N]; int n; int main() { //freopen("1.txt","r",stdin); cin>>n; int res=0; for(int i=1;i<=n;i++) { scanf("%d",&a[i]); res^=a[i]; } if(n&1) { puts("YES"); printf("%d ",n-2); for(int i=1;i<=n-2;i+=2) { printf("%d %d %d ",i,i+1,i+2); } for(int i=1;i<=n-4;i+=2) { printf("%d %d %d ",i,i+1,n); } } else { if(res) { puts("NO"); return 0; } puts("YES"); printf("%d ",n-3); for(int i=1;i<=n-3;i+=2) { printf("%d %d %d ",i,i+1,i+2); } for(int i=1;i<=n-4;i+=2) printf("%d %d %d ",i,i+1,n); } return 0; }
E.Yurii Can Do Everything
题意:给一个长为n的数组.定义一个区间是好的:区间端点的异或值等于区间其他数之和,问这样的区间有多少个.
题解:考虑固定左端点l,设a[l]的二进制最高位为k,向右暴力寻找满足条件的右端点,因为左端点的最高位为第k位,那么与另外一个数的异或值不会超过2^(k+1),因此如果中间的值超过2^(k+1),那么可以直接跳出寻找.
这样可以找出所有解区间.然后将区间翻转在找一遍,注意判重.
下面说明一下时间复杂度:对于一个右端点作为最高位为k时最多只能被两个左端点l扫到,因为如果超过两个,那么sum>=3*2^k则之前就跳出.因此,每个右端点作为最高位最多只会被两个l扫到,那么最多会被2logai区间扫到,对于每次扫描,一定会落在某个数上,因此总的时间复杂度为nlogai.
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=2e5+100; int a[N]; set<pair<int,int>>s; int main() { //freopen("1.txt","r",stdin); int n; cin>>n; for(int i=1;i<=n;i++) scanf("%d",&a[i]); ll ans=0; for(int i=1;i<=n;i++) { int k=0; for(int j=30;j>=0;j--) if(a[i]>>j&1) { k=j; break; } int sum=a[i+1]; for(int j=i+2;j<=n;j++) { if(sum>=(1<<k+1)) break; if((a[i]^a[j])==sum) { ans++; s.insert({i,j}); } sum+=a[j]; } } reverse(a+1,a+1+n); //cout<<ans<<endl; for(int i=1;i<=n;i++) { int k=0; for(int j=30;j>=0;j--) if(a[i]>>j&1) { k=j; break; } int sum=a[i+1]; for(int j=i+2;j<=n;j++) { if(sum>=(1<<k+1)) break; if((a[i]^a[j])==sum) { if(s.count({n-j+1,n-i+1})==0) ans++; } sum+=a[j]; } } cout<<ans<<endl; }