A. Adjacent Replacements
题意:对于每对数(1和2,3和4,...),替换之后留下的都是小的那个数,而小数都是奇数,所以从前往后处理,遇到偶数减一,奇数不变
C++代码如下:
#include<iostream>
using namespace std;
const int N=1010;
int a[N];
int n;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
int x;
cin>>x;
if(x%2)a[i]=x;
else a[i]=x-1;
}
for(int i=1;i<=n;i++)cout<<a[i]<<' ';
return 0;
}
B. Polycarp's Practice
题意:将数组分成k部分,要求每部分的最大值加起来最大,把每个数及其下标放在结构体中,对结构体按数进行从大到小排序,找出前k大的数,把他们的下标进行排序,按照下标找区间长度
C++代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
struct Node{
int x;
int id;
};
bool cmp1(Node a,Node b){
if(a.x!=b.x)return a.x>b.x;
return a.id<b.id;
}
Node st[2000+5];
int a[2000+5];
int b[2000+5];
int main(){
int n,k;
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>st[i].x;
st[i].id=i;
}
sort(st+1,st+1+n,cmp1);
int sum=0;//存储前k大的数
for(int i=1;i<=k;i++){
sum=sum+st[i].x;
a[i]=st[i].id;//前k大的数的下标
}
sort(a+1,a+1+k);//下标排序
for(int i=1;i<=k;i++){//根据下标进行求划分区间(关键在于第一个区间和最后一个区间)
if(i==1){
b[i]=a[i];
if(a[2]!=0)b[i]=b[i]+a[2]-a[1]-1;//重点
if(a[2]==0)b[i]=n;
}else if(1<i&&i<k){
b[i]=a[i+1]-a[i];
}else b[i]=n-a[i]+1;
}
cout<<sum<<endl;
for(int i=1;i<=k;i++){
if(i<k)printf("%d ",b[i]);
else printf("%d\n",b[i]);
}
return 0;
}
C. Three Parts of the Array
题意:将一个数组分成三块(可能有某块为空),能使左右两块相等的最大的相等值,每一块的值等于里面所有数的和,维护前缀和s[]和后缀和last[],用双指针寻找左右两块相等的最大值输出即可
C++代码如下:
#include<iostream>
using namespace std;
const int N=200010;
int a[N];
long long s[N],last[N];
int n;
int main(){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)s[i]=s[i-1]+a[i];
for(int i=n;i>=1;i--)last[i]=last[i+1]+a[i];
int i=0,j=n+1;
long long maxx=0;
while(i<j){
if(s[i]==last[j])maxx=s[i],i++,j--;
else if(s[i]<last[j])i++;
else j--;
}
cout<<maxx<<endl;
return 0;
}
D. Two Strings Swaps
题意:问字符串a要至少预交换几个字母才可以和b通过题目的三个操作使两个字符串相等
注意:只能换a中的字母
C++代码如下:
#include<iostream>
using namespace std;
int main(){
int n;
cin>>n;
string a,b;
cin>>a>>b;
int sum=0;
for(int i=0;i<(a.size()+1)/2;i++){
char a1,a2,b1,b2;
a1=a[i],a2=a[n-i-1],b1=b[i],b2=b[n-i-1];
if(i!=n-i-1){
//可以由三个操作使a,b相等
if(a1==a2&&b1==b2)continue;
if(a1==b1&&a2==b2)continue;
if(a1==b2&&a2==b1)continue;
//不能由三个操作使a,b相等
if(b1==b2||a2==b1||a1==b2||a2==b2||a1==b1)sum++;
else sum+=2;
}else if(a1!=b1)sum++;
}
cout<<sum<<endl;
return 0;
}
E. Military Problem
题意:遍历是先序遍历,用一个数组存储先序遍历的结果,记录每个节点在先序遍历中出现的下标,预处理以每个节点为根的子树中节点的数量
C++代码如下:
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
const int N=200010;
int h[N],e[N],ne[N],idx;
int s[N];
vector<int> v;
bool st[N];
int cnt[N];//cnt[i]记录以i为根的子树中的节点数量
int id[N];//id[i]保存每个节点在遍历时出现的下标
int n;
void add(int a,int b){
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
int dfs(int u){
v.push_back(u);
id[u]=v.size()-1;
st[u]=true;//标记当前点已经搜过
int sum=1;//sum记录以u为根节点的子树中的节点数量
for(int i=h[u];i!=-1;i=ne[i]){//遍历所有的子节点
int j=e[i];
if(!st[j])dfs(j);//如果没搜过,则搜
sum+=cnt[j];//加上cnt[j]
}
cnt[u]=sum;//保存以u为根节点的子树中的节点数量
return sum;//返回
}
int main(){
int n,q;
cin>>n>>q;
memset(h,-1,sizeof h);
for(int i=2;i<=n;i++)cin>>s[i];
//因为要从小到大遍历,所以建树的时候从大到小插入
for(int i=n;i>=2;i--)add(s[i],i);
dfs(1);//从根节点开始深搜,预处理所有的节点
while(q--){
int u,k;
cin>>u>>k;
//如果以u为根的子树中的节点数量小于k,则直接输出-1
if(cnt[u]<k)cout<<-1<<endl;
else cout<<v[id[u]+k-1]<<endl;
}
return 0;
}
F. Xor-Paths
题意:找到从左上角走到右下角的所有数的异或值等于k的所有方案,输出个数
C++暴力代码如下(会超时,但思路简单清晰):
#include<iostream>
using namespace std;
const int N=25;
typedef long long LL;
LL g[N][N];
LL n,m,ans,k;
void dfs(int u,int v,LL sum){
if(u==n&&v==m){
if(sum==k)ans++;
return;
}
//往右走
if(v+1<=m)dfs(u,v+1,sum^g[u][v+1]);
//往下走
if(u+1<=n)dfs(u+1,v,sum^g[u+1][v]);
}
int main(){
cin>>n>>m>>k;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>g[i][j];
dfs(1,1,g[1][1]);
cout<<ans<<endl;
return 0;
}
C++正解:写两个搜索函数,一个从头开始搜,一个从尾开始搜,每个都搜一半,用第二个函数搜索的时候进行判断
异或的性质:若a^b=c,则a^c=b,b^c=a
代码如下:
#include<iostream>
#include<map>
using namespace std;
const int N=22;
map<long long,int>v[N][N];
int n,m;
int half;
long long k;
long long a[N][N];
long long ans;
void dfs1(int x,int y,long long sum,int cnt){
sum^=a[x][y];
if(cnt==half){
v[x][y][sum]++;
return;
}
if(x+1<n)dfs1(x+1,y,sum,cnt+1);
if(y+1<m)dfs1(x,y+1,sum,cnt+1);
}
void dfs2(int x,int y,long long sum,int cnt){
if(cnt==n+m-2-half){
if(v[x][y].count(k^sum))
ans+=v[x][y][k^sum];
return;
}
if(x>0)dfs2(x-1,y,sum^a[x][y],cnt+1);
if(y>0)dfs2(x,y-1,sum^a[x][y],cnt+1);
}
int main(){
cin>>n>>m>>k;
half=(n+m-2)/2;//记录一半是多少
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cin>>a[i][j];
}
}
dfs1(0,0,0,0);
dfs2(n-1,m-1,0,0);
cout<<ans<<endl;
return 0;
}