A
如果一开始那个数就可以被3取余数,瓦尼亚先手改变了他的值,这样的话,这个数就再也不能被3整除了。其实仔细一想 , 只有 2 , 4 , -1 , 1这种数字,改变一下就能被整除的数字,瓦尼亚可以一次改变获得胜利,剩下的所有数字,瓦尼亚都赢不了
int n ;cin>>n;
//玩家可以加一 或者减一
if(!(n%3)){
cout<<"Second"<<'\n';
return;
}
if((n-1)%3 == 0 || (n+1)%3 == 0 || (n-1) == 0 || (n+1)==0){
cout<<"First"<<'\n';
return;
}
B
这题就稍微难一点了,感觉是前三题里面最难的,主要是因为题目看不懂,不好理解(我这种高考语文118的人都理解了半天【手动狗头】)。好了 ,这里就说一下题目是什么意思,首先有n个箱子,我们把他们分成若干组,每组里面都有k个箱子。我们就得到了第一个条件k要是n的因数
然后呢,找到每组的重量 , 举个例子, 假设被分成1,2, 3三组,1组的重量是8,2组的重量是9,三组的重量是2。然后计算出差值最大的数,在例子中就是 9-2 = 7;那么这个7就是被分成3组时的答案 ,找到最大答案
我们用前缀和来维护每一组的和,这样子的话查询效率就从On 变成O1了
1、首先是找到n的因数
for(int i =1;i<=n;++i){
if(n % i == 0){
int k =i; //k 的值 ,其实这步也可以不写
int t =result(k); //这是一个函数,我们一会来写这个函数
ans = max(ans , t);
}
}
这样子,基本框架就完成了
2、求出每组的和并找到差值最大的数
//刚刚的那个函数
int result(int k ){
int maxn =-1;
for(int i =1;i<=n;i +=k){
maxn = max(maxn , pre[i+k-1] - pre[i-1]); //找到了几组中和最大的数
}
//接下来找最小的
int minn = 1e15;
for(int i =1;i<=n;++i){
minn = min(minn , pre[i-1+k] -pre[i-1]);
}
return maxn - minn;
}
到这里就做完了
#include <bits/stdc++.h>
using namespace std;
#define PII pair<int,int>
#define int long long
const int N = 150010;
int a[N] , pre[N];
int n;
int result(int k){
int maxn = -1;
for(int i =1;i<=n;i +=k){
maxn = max(maxn , pre[i +k-1] - pre[i-1]);
}
int minn = 1e15;
for(int i =1;i<=n;i +=k){
minn = min(minn , pre[i +k-1] - pre[i-1]);
}
return maxn - minn;
}
void solve(){
cin>>n;
for(int i =1;i<=n;++i)cin>>a[i];
for(int i = 1;i<=n;++i)pre[i] = pre[i-1]+a[i];
int ans = -1;
for(int i =1;i<=n;++i){
if(n%i ==0){
int k = i; //k值
int t = result(k);
ans = max(ans , t);
}
}
cout<<ans<<'\n';
}
signed main(){
ios::sync_with_stdio(0),cout.tie(0),cin.tie(0);
int _;cin>>_;
while(_--)solve();
return 0;
}
C
这道题其实就是最长连续上升子序列的变式,动态规划去做,但是我们要知道奇偶数连续怎么表示,其实就是((a[i] +a[i-1])&1),看不懂位运算的话,其实就是这样((a[i] +a[i-1])%2 != 0)
#include <bits/stdc++.h>
using namespace std;
#define PII pair<int,int>
#define int long long
const int N = 2e5+9;
int a[N] , dp[N];
void solve()
{
int n;cin>>n;
for(int i =1;i<=n;++i)cin>>a[i] , dp[i] = a[i];
int ans = -1e9;
for(int i =1;i<=n;++i){
if((a[i]+a[i-1])&1)dp[i] = max(dp[i-1]+a[i] , dp[i]);
ans = max(ans , dp[i]);
}
cout<<ans<<'\n';
}
signed main(){
ios::sync_with_stdio(0),cout.tie(0),cin.tie(0);
int _;cin>>_;
while(_--)solve();
return 0;
}
D
这题要求给定数列 a,求有多少对 (i,j) 满足 (2ai)(2aj)=(2aj)(2ai)。
我们可以把式子化简一下,我是用了取对数的方式,就变成 2^aj ln(2^ai) = 2^ai ln(2^ai)
我们可以看出只有ai = aj , ai =1 &&aj=2 , ai=2&&aj=1这三种情况的时候才能够满足题意
那么我们就可以用map来存放
#include <bits/stdc++.h>
using namespace std;
#define PII pair<int,int>
#define int long long
const int N = 2e5+9;
int a[N] ;
void solve()
{
map<int,int>mp;
int n;cin>>n;
for(int i =1;i<=n;++i){
cin>>a[i];
mp[a[i]]++;
}
int ans = 0;
for(auto [x,y]:mp){
ans +=y*(y-1)>>1;
}
ans +=mp[2]*mp[1];
cout<<ans<<'\n';
}
signed main(){
ios::sync_with_stdio(0),cout.tie(0),cin.tie(0);
int _;cin>>_;
while(_--)solve();
return 0;
}
E
我们只需要观察最小值,因为一旦最小值到了第一位,他将会永远在第一位,他后面的数就排不了序了,所以我们只需要看最小值后面的数有没有排好序,排好序的话,就有答案,答案是最小值的位置-1 , 反之就输出-1 。 还有需要注意的是,最小值是第一个出现的最小值
#include <bits/stdc++.h>
using namespace std;
#define PII pair<int,int>
#define int long long
#define INF 0x3f3f3f3f
const int N = 2e5+9;
int a[N] ;
void solve()
{
int minn =1e10;
int idx = 0;
int n;cin>>n;
for(int i =1;i<=n;++i){
cin>>a[i];
if(a[i] <minn){
minn = a[i];
idx = i;
}
}
//idx 记录了第一个最小值的位置
bool f = true;
for(int i =idx+1;i<n;++i){
if(a[i] >a[i+1])f = false;
}
if(f)cout<<idx-1<<'\n';
else cout<<-1<<'\n';
}
signed main(){
ios::sync_with_stdio(0),cout.tie(0),cin.tie(0);
int _;cin>>_;
while(_--)solve();
return 0;
}