题目链接
A. Submission Bait
这是一道博弈题,比较简单,但是赛时直接就WA了两发,刚开始把题想简单了,第二发没有考虑清楚。
题意:一串数字,Alice如果选了6,那么Bob必须选择大于等于6的数,然后Alice再选择大于等于Bob的数字,如此以往,谁选不到谁就输了
思路:将每个数字出现的次数统计起来,从大到小遍历每个数字出现的次数,如果有一个是奇数的话,Alice就赢,否则就Bob赢。
因为假如是5,5,5,5,5,4,3,1,4,2的排列的话,我Alice直接选最大的5,那Bob就只能选5,选到最后一定是Bob输,我们用一个map数组,然后从后往前遍历,出现奇数个的就输出YES,否则到最后再输出NO
#include <bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define fi first
#define se second
#define PII pair <int,int>
#define ALL(x) x.begin(),x.end()
#define lowbit(x) (x&(-x))
using namespace std;
const int N = 1e6+5;
int mp[N];
int a[N];
void solve () {
memset(mp,0,sizeof(mp));
int n;cin>>n;
for (int i=1;i<=n;i++) {
cin>>a[i];mp[a[i]]++;
}
for (int i=50;i>=1;i--) {
if (mp[i]) {
if (mp[i]&1) {
cout<<"YES"<<'\n';return ;
}
}
}
cout<<"NO"<<'\n';
}
signed main () {
IOS;
int T =1;
cin>>T;
while(T--) solve ();
return 0;
}
B. Array Craft
这是一道构造题,让构造出一个数组满足以上的条件:
- 最大前缀的最小位置在x
- 最大后缀的最大位置在y
- 数组都是1或者-1
我一开始的思想是将x,y里面的数字全部变成1,以外的数字都是-1.但是赛时我发现了,这样就不满足前两个条件了如果是-1,-1,-1,-1,-1,1,1,1,-1,-1,-1,-1这样的数组,从前加到最后一个1值是-2,但是从前往后加为-2的地方的最小的位置是第二个-1的位置,所以我们要构造前面加起来大于-2的值,那为什么是-2呢,因为x,y之间的和最小就是2,而且在y-1和x+1的位置都要是-1,然后再往两边构造,-1,1交替出现
#include <bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define fi first
#define se second
#define PII pair <int,int>
#define ALL(x) x.begin(),x.end()
#define lowbit(x) (x&(-x))
using namespace std;
const int N = 1e5+5;
int a[N],b[N];
void solve () {
//如果在这里对a,b数组初始化的话,会降低效率,容易超时,我就超了一次
int n,y,x;cin>>n>>y>>x;
int k=0;
for (int i=x-1;i>=1;i--) {
if (k%2==0)
a[++k]=-1;
else a[++k]=1;
}
for (int i=k;i>=1;i--) cout<<a[i]<<' ';
for (int i=x;i<=y;i++) cout<<"1"<<' ';
k=0;
for (int i=y+1;i<=n;i++) {
if (k%2==0)
b[++k]=-1;
else b[++k]=1;
}
for (int i=1;i<=k;i++) cout<<b[i]<<' ';
}
signed main () {
IOS;
int T =1;
cin>>T;
while(T--) solve ();
return 0;
}
C. Mad MAD Sum
一道难度不小的思维题我认为,数组在经过第一次变化之后会变成一个非递减序列,我们将样例多变化几次就可以发现似乎是在每次向右移动一位一样,例如:1,2,3,4,5,5,6,7,7,9,6,5,9,9会变化成0,0,0,0,0,5,5,5,7,7,7,7,9,9,然后变化成0,0,0,0,0,0,5,5,5,7,7,7,7,9,然后变成0,0,0,0,0,0,0,5,5,5,7,7,7,7可以看出来向右移动一位。但是不都是这样的,例如2,1,1,2,2,2变成0,0,1,2,2,2,变成0,0,0,0,2,2就不是单纯向右移动一位了,只有一个一样的就是会出现这种情况,我们只需要将原数组操作两次就可以往右一直移动求和了。
#include <bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define fi first
#define se second
#define PII pair <int,int>
#define ALL(x) x.begin(),x.end()
#define lowbit(x) (x&(-x))
using namespace std;
const int N = 1e6+5;
int a[N],b[N];
void solve () {
int n;cin>>n;int sum=0;
for (int i=1;i<=n;i++) {
cin>>a[i];sum+=a[i];
}
if (n==1) {
cout<<sum<<'\n';return ;
}
int f=1;int flag=1;int cnt=0;int pos=0;
map<int,int>mp;int my=0;
for (int i=1;i<=n;i++) {
mp[a[i]]++;
if(mp[a[i]]>=2) {
if (a[i]>my) my=a[i];
}
a[i]=my;sum+=my;
}
map<int,int>mp1;my=0;
for (int i=1;i<=n;i++) {
mp1[a[i]]++;
if(mp1[a[i]]>=2) {
if (a[i]>my) my=a[i];
}
if (my==0) cnt++;
a[i]=my;pos+=my;
}
int t=n-cnt;
for (int i=1;i<=t;i++) {
sum+=pos;
pos-=a[n-i+1];
}
cout<<sum<<'\n';
}
signed main () {
IOS;
int T =1;
cin>>T;
while(T--) solve ();
return 0;
}