【解题报告】CF DIV2 #ROUND 721 A~C
比赛链接
比赛评价:
A题码了后实在太累了,明天还要早训就没交题,白天补的题目。
各位还是要注意身体健康呀,这几天感觉确实不大对劲。
A. And Then There Were K
题意
找到最大的k满足上面的式子
思路
比较简单1发AC
先暴力打了一遍程序找的规律
不过据说有人用pow实现的,然后WA了
代码
// Problem: A. And Then There Were K
// Contest: Codeforces - Codeforces Round #721 (Div. 2)
// URL: https://codeforces.com/contest/1527/problem/A
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// FishingRod
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
typedef pair<int,int> PII;
#define MULINPUT
/*DATA & KEY
*/
int T;
LL quick(LL a,LL b)
{
LL res=1;
a=a;
while(b)
{
if(b&1) res=(res*a);
a=(a*a);
b>>=1;
}
return res;
}
void solve(int C)
{
//NEW DATA CLEAN
//NOTE!!!
int n;cin>>n;
int k=int(log2(n));
cout<<quick(2,k)-1<<endl;
}
int main()
{
#ifdef MULINPUT
scanf("%d",&T);
for(int i=1;i<=T;i++)solve(i);
#else
solve(1);
#endif
return 0;
}
B1. Palindrome Game (easy version)
字符串+博弈论
题意
easy version初始给定的是一个01回文串
Alice和Bob可以依次进行下面两个操作
1.如果s[i]=0,那么花费1使得s[i]=1
2.如果这个串不是回文串可以选择反转整个字符串,但是如果一个人选择了反转,那么后面那个人不能在下一步操作中也选择反转
Alice先手
如果全为1了,那么游戏结束。此时比较两人花费,谁花的少谁赢。
思路
字符串状态转移图
为了赢得游戏,每个人的最优策略应当是让对手尽可能进入回文状态/非回文已经翻转状态,这样就能迫使对方花费更多,并且如果可以同时从非回文进入已翻转和回文状态,选择翻转减少自己花费
(需要做一些特判<=2的时候)
根据这一规则删除一些不必要的路线
由于这题easy版本开局必是回文的所以只要考虑奇数回文和偶数回文状态即可
代码
// Problem: B1. Palindrome Game (easy version)
// Contest: Codeforces - Codeforces Round #721 (Div. 2)
// URL: https://codeforces.com/contest/1527/problem/B1
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// FishingRod
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
typedef pair<int,int> PII;
#define MULINPUT
/*DATA & KEY
*/
int T;
void solve(int C)
{
//NEW DATA CLEAN
//NOTE!!!
int n;cin>>n;
string s;cin>>s;
int cnt=0;
for(int i=0;i<n;i++)
if(s[i]=='0')cnt++;
if(cnt==1)puts("BOB");
else if(cnt&1)puts("ALICE");
else puts("BOB");
}
int main()
{
#ifdef MULINPUT
scanf("%d",&T);
for(int i=1;i<=T;i++)solve(i);
#else
solve(1);
#endif
return 0;
}
B2. Palindrome Game (hard version)
题意:
easy加强版本,区别是开局给的不一定是回文串
思路
细节没处理出来,主要是消路线的时候没考虑清楚有些路是必须走的。后来看了大佬的视频发现不应该这么想的
大佬的解题视频 分别统计对称0的个数和非对称0的个数
如果非对称0的个数是0,那就是easy版本
如果非对称0的个数不是0,那么一开始Alice就可以选择翻转字符串,并且可以一直进行直到BOB把字符串变成回文的,显然ALICE的优势会越来越大。如果最终变为回文的,那么BOB最多可以取得1次的优势,那么局面最多会被拉平,否则仍旧是ALICE胜利。既然ALICE优势会越来越大,那么考虑最开始只有1个非对称,ALICE优势最小的情况,可以发现BOB能够扳回一局实现平局。
代码
// Problem: B2. Palindrome Game (hard version)
// Contest: Codeforces - Codeforces Round #721 (Div. 2)
// URL: https://codeforces.com/contest/1527/problem/B2
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// FishingRod
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
typedef pair<int,int> PII;
#define MULINPUT
/*DATA & KEY
*/
int T;
const int N=1e3+10;
char s[N];
void solve(int C)
{
//NEW DATA CLEAN
//NOTE!!!
int n;cin>>n;
cin>>(s+1);
LL sum=0,summ=0;
for(int i=1;i<=(n+1)/2;i++)
if(s[i]!=s[n-i+1])sum++;//非对称0
for(int i=1;i<=n;i++)
if(s[i]==s[n-i+1]&&s[i]=='0')summ++;//对称0
if(sum==0){
if(summ%2==0||summ==1)puts("BOB");
else puts("ALICE");
}
else{
if(summ==1){
if(sum==1)puts("DRAW");//回文对称状态只有1,BOB扳回一局,实现平局
else puts("ALICE");
}
else puts("ALICE");
}
}
int main()
{
#ifdef MULINPUT
scanf("%d",&T);
for(int i=1;i<=T;i++)solve(i);
#else
solve(1);
#endif
return 0;
}
C. Sequence Pair Weight
题意
定义一个序列的权重为序列中值相同的无序对数量,即
求a所有子段(长度>=2)权重和
思路
对于每一对符合条件的,题目可以给个区间做贡献
如果暴力枚举肯定会T,接下来考虑如何优化。
对于同一值a,我们有这些坐标的值等于a
我们展开暴力枚举(固定右边的来枚举)
我们可以发现如果右端点固定,后面那一项是相同的,那么可以对前面的进行合并
对第一项,我们可以做前缀和优化
我们一边输入一边维护值a的前缀和(继续%一下大佬的代码,还是参考B2视频的大佬)
原本想用vector维护,结果写得非常冗余
代码
// Problem: C. Sequence Pair Weight
// Contest: Codeforces - Codeforces Round #721 (Div. 2)
// URL: https://codeforces.com/contest/1527/problem/C
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// FishingRod
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
typedef pair<int,int> PII;
#define MULINPUT
/*DATA & KEY
*/
int T;
const int N=1E5+10;
LL a[N];
void solve(int C)
{
//NEW DATA CLEAN
map<LL,LL>mp;//mp维护前缀和
//NOTE!!!
int n;cin>>n;
LL sum=0;
for(int i=1;i<=n;i++){
LL x;cin>>x;
if(!mp.count(x)){
mp[x]+=i;
}
else{
sum+=mp[x]*(n-i+1);//贡献
mp[x]+=i;
}
}
cout<<sum<<endl;
}
int main()
{
#ifdef MULINPUT
scanf("%d",&T);
for(int i=1;i<=T;i++)solve(i);
#else
solve(1);
#endif
return 0;
}
反思
A:
对于区间答案相同的,主要看这几个方面找规律
先单独看
左端点/右端点变换规律
区间长度变化规律
答案变化规律
数字敏感度
1,3,5,7,15,31
B:
博弈游戏通常考虑
怎么让对面处于不利局面,让自己处于有利局面
C:
对于有easy和hard版本的题目,可以考虑先单独把easy版本情况分开
D:
对所有子区间/子段求点对贡献和,可以考虑点对端点被包含在哪些区间里,然后考虑单个点对可以对多少个区间做贡献。
暴力枚举固定某一端点展开,合并同类项可以考虑前缀和做优化
如果要维护到某一位置,某一个值的前缀和,可以考虑用map来维护