A.And Then There Were K
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
int main() {
int t;
cin >> t;
while (t--) {
ll a;
cin >> a;
int cnt = 0;
while (1) {
if (a >> 1)cnt++;
else break;
a >>= 1;
}
cout << (int)pow(2, cnt) - 1 << '\n';
}
}
B.Palindrome Game (easy version)
如题所示,有两种操作
- 花一块钱 将一个0改成1
- 不花钱 翻转
思路:
因为给的是回文,所以第一步女生必然花一块钱。
首先我们记录0的个数为cnt
那么:
- cnt==0,显然“DRAW”
- cnt==1,显然是“BOB”
- 以上是俩特判
- cnt%2==0,也就是有偶数多个0,由于是回文,所以0的位置是对称的,那么女生花一块钱之后,男生也可以在女生操作的对称位置花一块钱,直到剩下一个0,那这时候男生选择翻转,女生就又得花一块钱了,也就是说这种情况男生必胜。
- 剩下的都是女生的必胜局,为什么呢?因为如果有奇数多个0,代表回文长度也是奇数,而且正中间必然是0,那女生可以把正中间的0改成1,接下来就与上面同理了,只是因为这样算是男生先手,所以女生必胜。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=1e3+7;
int a[N];
int main(){
int t;
cin>>t;
while(t--){
int n;
cin>>n;
int cnt=0;
for(int i=1;i<=n;i++){
scanf("%1d",&a[i]);
if(a[i]==0)cnt++;
}
if(cnt>0&&cnt%2==0){
cout<<"BOB"<<'\n';continue;
}
if(cnt==0){
cout<<"DRAW"<<'\n';continue;
}
if(cnt==1){
cout<<"BOB"<<'\n';continue;
}
cout<<"ALICE"<<'\n';
}
}
看榜时发现这题居然卡了众多大佬,有点吃惊。
C. Sequence Pair Weight
暴力枚举不可取,所以要想新思路
假设数组下标从1开始:
设最终答案为res。
每当遇到一对值相等的元素,记录其下标为i和j,那么它对res的贡献是i*(n-j+1)
下面我解释一下这个公式:
i向左有i个数,j向右有(n-j+1)个数(包括本身)。
假设i==3,j==5,那么区间[3,5]算一次答案,区间[2,5]也算一次答案
区间[3,6]也算一次答案....等等等等,总的来说就是一共有i(n-j+1)个区间包
含了区间[i,j]。
接下来很容易想到一种方法:
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
if(a[i]==a[j]){
res=res+i*(n-j+1)
}
}
}
但是很遗憾,这种方法会超时,所以这时候可以用map来提高效率
以样例1 2 1 1为例子(**假设数组下标从1开始**)
现在对于a[4]来说,a[1]和a[3]都是符合条件的,那么
res=res+1*(4-4+1)+3*(4-4+1)
上面那条式子可以写成res+=(1+3)*(4-4+1)
那么下面的AC代码就呼之欲出了(没看懂的话请直接看代码)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
using namespace std;
typedef long long ll;
int main(){
int t;
cin>>t;
while(t--){
map<int,ll>a;
ll res=0;
int n;cin>>n;
for(int i=1;i<=n;i++){
int x;cin>>x;
res+=a[x]*(n-i+1);
a[x]+=i;
}
cout<<res<<'\n';
}
}