首页 > 其他分享 >【解题报告】CF DIV2 #ROUND 717 A~C D(只有思路)

【解题报告】CF DIV2 #ROUND 717 A~C D(只有思路)

时间:2022-11-25 20:37:15浏览次数:63  
标签:717 CF int 异或 数组 区间 互质 DIV2 dp


【解题报告】CF DIV2 #ROUND 717 A~D

​比赛链接​​ 排名3694,终于上分了,回归pupil好耶

【解题报告】CF DIV2 #ROUND 717 A~C D(只有思路)_数组

A. Tit for Tat

思路
简单的贪心,字典序最小那就让前面的-1,然后+1全部加到最后一个数上即可
代码

// Problem: A. Tit for Tat
// Contest: Codeforces - Codeforces Round #717 (Div. 2)
// URL: https://codeforces.com/contest/1516/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
t 1 20
n 2 100
k 1 10000
ai 0 100
*/
int T;
const int N=205;
int a[N];
void solve(int C)
{
//NEW DATA CLEAN
memset(a,0,sizeof a);
//NOTE!!!
int n,k;cin>>n>>k;
for(int i=1;i<=n;i++)cin>>a[i];
int pos=1;
while(k--)
{
while(a[pos]<=0)pos++;
if(pos>=n)break;
a[pos]--,a[n]++;
}
for(int i=1;i<=n;i++)cout<<a[i]<<" ";
puts("");

}

int main()
{
#ifdef MULINPUT
scanf("%d",&T);
for(int i=1;i<=T;i++)solve(i);
#else
solve(1);
#endif
return 0;
}

B. AGAGA XOOORRR

思路
比较有意思的一题,很多人FST了不清楚为啥,主要思想是异或前缀和。
原本用前后缀写了个假算法,后来找到数据发现假了

方法比较多吧。讲讲大致思路,题目说可以把两个相邻的数替换成他们的异或值,问最后能不能把数组里的值都变成一样的,数组值的数量至少为2

其实嘛,就是把这个数组化成几个块,然后这几个块组内异或成一个值。问有没有办法让他们异或出来的值都相等

【解题报告】CF DIV2 #ROUND 717 A~C D(只有思路)_i++_02


我们从最终结果考虑,那么分为两种情况,假设最终的值都为X,任意数量都可以化成三个或者两个块(其实到这里的话你可以暴力枚举分界线,一条分界线和两条分界线)

例如
X ^ X ^ X ^ X=X ^ X
X ^ X ^ X ^ X ^ X= X ^ X ^ X

如果块为奇数,那么X ^ X ^ X =X,也就是全部异或起来为X

然后利用异或前缀和,找到前缀和为X的第一个位置POS1,然后反向找一个前缀和为0的位置POS2,如果POS1 POS2都存在并且POS1<POS2那么就输出YES

【解题报告】CF DIV2 #ROUND 717 A~C D(只有思路)_数组_03

如果块为偶数,那么X ^ X =0,也就是全部异或起来为0直接输出YES就完事了
除了以上情况都输出NO
代码

// Problem: B. AGAGA XOOORRR
// Contest: Codeforces - Codeforces Round #717 (Div. 2)
// URL: https://codeforces.com/contest/1516/problem/B
// 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
t 1 15
n 2 2000
ai 0 2^30
*/
int T;
const int N=2E3+10;
LL a[N],pre[N];
void solve(int C)
{
//NEW DATA CLEAN
memset(a,0,sizeof a);
memset(pre,0,sizeof pre);
//NOTE!!!
int n;cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
pre[1]=a[1];
for(int i=2;i<=n;i++)pre[i]=pre[i-1]^a[i];
if(pre[n]==0){puts("YES");return;}
int pos1,pos2;
bool flag=0;

for(int i=1;i<=n;i++)
if(pre[i]==pre[n])
{pos1=i;break;}
for(int i=n;i>=1;i--)
if(pre[i]==0)
{pos2=i;flag=1;break;}

if(flag&&(pos1<pos2))puts("YES");
else puts("NO");
}

int main()
{
#ifdef MULINPUT
scanf("%d",&T);
for(int i=1;i<=T;i++)solve(i);
#else
solve(1);
#endif
return 0;
}

C. Baby Ehab Partitions Again

【解题报告】CF DIV2 #ROUND 717 A~C D(只有思路)_i++_04

思路
题意:定义一个好的数组:将他的元素不重不漏地划分成两个子序列,不存在一种划分方式使得两个子序列的和是相等的。现在给你长度为n的一个数组,你可以删除其中的一些数,来让他成为一个好数组,问最少删除几个

两个子序列下意识会想到01背包选与不选的操作吧。然后这题是利用了奇数偶数的性质,很妙啊。

首先思考一下最简单的情况,如果数组和为奇数,那么一定是好数组。

然后是偶数的,首先01背包看能不能分出来。

如果不能分出来,那么皆大欢喜,不用删除。

如果能分出来,那就要去掉数了,实际上只要去点任意一个数就可以了。数组里有奇数那么直接去掉奇数就可以了,因为剩下和为奇数不可分。如果全是偶数的话,那么对所有元素除2,直到出现奇数,然后删掉这个数就可以了。(为啥可以除2呢?我们已经确定进入这个分支的数组是可以划分成两个和相同的子序列的,那么这个结果对于除2知乎的数组是一样的,那么已知转化到出现奇数即可)实际上,我们可以直接除这个数组的公约数,然后看哪个数是奇数。

【解题报告】CF DIV2 #ROUND 717 A~C D(只有思路)_i++_05

代码

// Problem: C. Baby Ehab Partitions Again
// Contest: Codeforces - Codeforces Round #717 (Div. 2)
// URL: https://codeforces.com/contest/1516/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
n 2 100
ai 1 2000
*/
int T;
const int N=105,M=2e5+10;
LL a[N],f[M];
void solve(int C)
{
//NEW DATA CLEAN

//NOTE!!!
int n,pos;cin>>n;
bool flag=0;
LL sum=0,g=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum+=a[i];g=__gcd(g,a[i]);
if(a[i]&1&&!flag)
{
flag=1;
pos=i;
}
}

if(sum&1)puts("0");
else
{
for(int i=1;i<=n;i++)
for(int j=sum/2;j>=a[i];j--)
f[j]=max(f[j],f[j-a[i]]+a[i]);

if(f[sum/2]==sum/2)
{
puts("1");
if(flag)cout<<pos<<endl;
else
{
for(int i=1;i<=n;i++)
if((a[i]/g)&1)
{
cout<<i<<endl;
break;
}
}
}
else puts("0");

}
}

int main()
{
#ifdef MULINPUT
scanf("%d",&T);
for(int i=1;i<=T;i++)solve(i);
#else
solve(1);
#endif
return 0;
}

D. Cut(待补)

【解题报告】CF DIV2 #ROUND 717 A~C D(只有思路)_#define_06

思路
这题只学了思路等我学了倍增DP再来瞅瞅,丢一道牛客例题:​​​区间的连续段​

题意给你长度为n的数字,有q次查询。每次查询区间[l,r],要求对这个区间内的数分块,对于每个分块,他们的LCM=他们的乘积,也就是块内元素互质,gcd=1,问最少分多少块
​​参考这位大佬的博客(双指针版本+倍增)​​ 主要是倍增思想的优化DP,没接触过的玩意呢
搜了一下资料,可以参考一下这篇超级萌的解说!

①条件转化
如何让组尽可能的少?一个显然的思想是让每组长度尽可能地长,装的元素尽可能多。
那么如何确定最长能扩展到哪里呢?
由区间LCM=元素乘积–>区间元素两两互质–>分解质因数后,待加入a[i]分解出来的数是原来区间没有的

!!!需要注意的是,在第一段推理过程中不能说成,因为区间LCM=元素乘积->区间gcd=1->两两互质(加粗的这段推理是不正确的,区分两两互质和整体互质)
但是这样是可以的区间LCM=元素乘积->两两互质->区间gcd=1

②预处理每个(暴力枚举1~n)起点最远能扩展到的地方
这部分还参考了​​这篇博客​​ 双指针一个个移动优化为倍增移动
预处理【解题报告】CF DIV2 #ROUND 717 A~C D(只有思路)_数组_07的区间都互质,【解题报告】CF DIV2 #ROUND 717 A~C D(只有思路)_数组_08与区间内的某个数不互质
倍增优化
定义
【解题报告】CF DIV2 #ROUND 717 A~C D(只有思路)_i++_09为从起点i,跳【解题报告】CF DIV2 #ROUND 717 A~C D(只有思路)_#define_10次能到的地方
状态转移:
【解题报告】CF DIV2 #ROUND 717 A~C D(只有思路)_i++_11
③倍增查询
不是很懂

代码
由于本人实在太弱鸡,只能照抄官方代码加解释了

#include <bits/stdc++.h>
using namespace std;
#define MX 100000
vector<int> p[100005];
int a[100005],nex[100005],dp[20][100005];//nex数组
int main()
{
int n,q;
scanf("%d%d",&n,&q);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
for (int i=2;i<=MX;i++)//类似埃筛预处理一波
{
if (p[i].empty())
{
nex[i]=n+1;
for (int j=i;j<=MX;j+=i)
p[j].push_back(i);
}
}
dp[0][n+1]=n+1;//起点n+1,跳2^0次能到的地方
for (int i=n;i>0;i--)
{
dp[0][i]=dp[0][i+1];
for (int j:p[a[i]])
{
dp[0][i]=min(dp[0][i],nex[j]);
nex[j]=i;
}
}
//预处理部分
for (int i=1;i<20;i++)
{
for (int j=1;j<=n+1;j++)
dp[i][j]=dp[i-1][dp[i-1][j]];
}
//查询部分
while (q--)
{
int l,r,ans=0;
scanf("%d%d",&l,&r);
for (int i=19;i>=0;i--)//这部分看由几个完整的区间
{
if (dp[i][l]<=r)
{
ans+=(1<<i);
l=dp[i][l];
}
}
printf("%d\n",ans+1);
}
}

反思

A:

手速贪心即可

B:

从最终结果形式反推思考
分块思想,思考每一块要满足的性质,分块问题有时候我们暴力枚举分割线
异或前缀和,要运用好x^x=0,x ^ 0=x这两个来推断区间值
值相同的时候,几个异或结果可以合并

C:

两组可以联想到01背包。
如果两个数相同,他们的和一定为偶数
这题引出奇偶性的切入点是最开始最简单的情况,整体和为奇数。

D:

区间LCM=元素乘积->两两互质->区间gcd=1
如何让组尽可能的少?一个显然的思想是让每组长度尽可能地长,装的元素尽可能多。
找最长满足条件的区间:双指针,双指针移动可以用倍增优化

补一个博客(D题里由链接)里看到的双指针伪代码模板

int L=1,R=1;
while(R<=n)
{
add(a[R]);
while(当前状态不符合)
{
delete(a[L]);
L++;
}
记录(a[L]~a[R])对应答案;
R++;
}


标签:717,CF,int,异或,数组,区间,互质,DIV2,dp
From: https://blog.51cto.com/u_15891800/5887725

相关文章

  • [DP/贪心 时间] P1717 钓鱼
    [DP时间]P1717钓鱼​​题目链接​​题目思路贪心可以做的比较简单,不过这里打算练习一下DP写法为了简化计算,把5分钟设为单位时间状态表示表示走到第i个湖钓鱼,耗时j属性:ma......
  • 【解题报告】CF DIV2 #ROUND 715 A~D
    【解题报告】CFDIV2#ROUND715A~D​​比赛链接​​​rating,已经无所谓了hhB想了个假算法,卡了半天,C也没时间看,我蠢爆了。A.AverageHeight思路速A了,先把奇数全部输出,然......
  • 【解题报告】CF DIV2 #ROUND 716 A~C
    【解题报告】CFDIV2#ROUND716A~C​​比赛链接​​​数学场/规律场A题5分钟速切,B题开始没看懂先看了C,发现C整不来,B整了半天打表找规律一发AC。D貌似要分块莫队之类的还......
  • CF889E Mod Mod Mod
    CF889EModModMod一道有趣的题,考虑\(x\)有意义的取值,设\(f_i\)表示\(x\bmoda_1...\bmoda_i\)的值,那么一定存在\(f_k=a_k-1\),否则我们可以让\(x\)整体加一直到......
  • CF1637H Minimize Inversions Number
    MinimizeInversionsNumber首先考虑\(k=1\),记\(g_i=\sum_{j=1}^{i-1}[p_i<p_j]-\sum_{j=1}^{i-1}[p_i>p_j]\),那么\(g_i\)表示将\(i\)移向最前面逆序......
  • 【解题报告】CF DIV3 #ROUND 734 A~D1
    【解题报告】CFDIV2#ROUND707A~D​​比赛链接​​比赛评价:一般性,有段时间没打了,甚至忘记多组输入hh。顺便吐槽一下翻译软件确实不行,以后还是直接看英文好了A.Polycarp......
  • WCF必知必会以及与Webapi的区别
    快速阅读介绍wcf中的信息交换模式MEP以及数据在传输过程中的序列化,endpont的介绍和wcf的三种实例模式以及安全模式以及和Webapi的简单对比wcf介绍支持跨平台,多种协议tcp,......
  • CF804E The same permutation
    首先当\(n\equiv\left\{\begin{matrix}2,3\end{matrix}\right\}\pmod4\)时,无解,因为每次操作一定会改变逆序对奇偶性。那就只剩两种情况先考虑\(n\equiv0\pmod......
  • CF1539E Game with Cards
    把最终答案看成一段\(0\),一段\(1\)的一个串。如果说我们的答案中有一段\(0\)(\(1\)同理)。那么所有\(0\)的数都满足所有第一个范围,这段\(0\)前面的\(1\)代......
  • CF1707D Partial Virtual Trees
    首先真子集这一限制比较麻烦,我们可以尝试把这个限制给去除掉。具体地,令\(G(i)\)表示答案,\(F(i)\)为用\(i\)步使得\(U={1}\)且不要求真子集这一限制的方案数。考虑......