这场是打的真不好,写一下题解总结一下自己叭。
比赛链接:https://codeforces.ml/contest/1350
放一下队友链接:
核心选手:https://me.csdn.net/qq_43559193
核心选手:https://me.csdn.net/weixin_43916298
目录
Codeforces Round #641 (Div. 2)
A. Orac and Factors
Code:
B. Orac and Models
Code:
C. Orac and LCM
Code:
D. Orac and Medians
Code:
Just Another Code:
先开的B,A就没细看。
题意:
定义f(x)操作为x的最小的因子(除1以外),对x进行嵌套f函数,问嵌套k次之后的结果
题目思路:
水了:
若C=A*B ,那么C+A=A+A*B=A*(B+1),此时的最小的因子,是A,B最小的因子+1,所以只能为2
所以只需要求一个因子 ,其余+2*(m-1)即可
/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(2)
#include
#include
#include
#include
#include
#include
#define debug(x) cout<<#x<<":"< pp;
const ll INF=1e17;
const int maxn=2e5+6;
const int mod=998244353;
const double eps=1e-3;
inline bool read(ll &num)
{char in;bool IsN=false;
in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
ll num[maxn];
ll dp[maxn];
int main()
{
int T;scanf("%d",&T);
while(T--){
read(n);read(m);
ll ans=0;
for(int i=2;i<=n;i++){
if(n%i==0){
ans=i;
break;
}
}
n+=ans;
n+=(m-1)*2;
printf("%lld\n",n);
}
return 0;
}
题目大意:
求一个下标单调递增且互为倍数,且满足若i>j,则si>sj的最长子序列
题目思路:
先做的B ,都卡了十分钟,服..
原因在哪呢?题意读错了,题意读的是:求一段子序列,子序列中的数互为因子数的递增最长序列。
离谱的是:样例 1 3 6 刚好在序列里都有,害。
总结:不要盲目看样例猜题了
以上均为吐槽
进入正题,其实简单,按照筛法的调和级数趋近于nlgn的思路,将下标用调和级数判断,这样因子数可以预处理出来,剩下的用个dp转移一下最长子序列就可以了。1e5之前因子最多240个,复杂度:lim->O(240*n)
/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(2)
#include
#include
#include
#include
#include
#include
#define debug(x) cout<<#x<<":"< pp;
const ll INF=1e17;
const int maxn=2e5+6;
const int mod=998244353;
const double eps=1e-3;
inline bool read(ll &num)
{char in;bool IsN=false;
in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
ll num[maxn];
ll dp[maxn];
vectorv[maxn];
int main()
{
int T;scanf("%d",&T);
while(T--){
read(n);
ll maxl=0;
for(int i=1;i<=n;i++) read(num[i]);
for(int i=1;i<=n;i++) v[i].clear();
for(int i=1;i<=n;i++)
for(int k=i*2;k<=n;k+=i)
if(num[k]>num[i])
v[k].push_back(i);
for(int i=1;i<=n;i++){
dp[i]=1;
for(int x:v[i]){
dp[i]=max(dp[i],dp[x]+1);
}
maxl=max(maxl,dp[i]);
}
printf("%lld\n",maxl);
}
return 0;
}
题目大意:
定义lcm为两个数的最小公倍数,问所有对的最小公倍数的最大公约数是多少?
题目思路:
开始思路是对的,越调越离谱
最大公约数与最小公倍数绝对考虑唯一分解定理,考虑每一个质因子的贡献:
所以:
所以由此看出只需要找组合中每一个p1因子的幂可能出现的最小值
1.如果出现有两个以上的数不存在该质因子,那么此时这两数lcm p1的幂为0,也就是说最大公约数p1的幂为0
2.如果出现有一个不存在该质因子,那么该质因子与最小的组合,即为最小幂
3.如果所有数都有该质因子,那么该质因子最小幂为第二小(不难理解吧)
/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(2)
#include
#include
#include
#include
#include
#include
#define debug(x) cout<<#x<<":"< pp;
const ll INF=1e17;
const int maxn=2e5+6;
const int mod=998244353;
const double eps=1e-3;
inline bool read(ll &num)
{char in;bool IsN=false;
in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
ll num[maxn];
int prime[maxn];
int vis[maxn];
int cnt=0;
vectorg[maxn];
void set_prime()
{
for(int i=1;i1) g[temp].push_back(1);
}
ll ans=1;
for(int i=1;i<=cnt;i++){
if(g[prime[i]].size()<=n-2) continue;
sort(g[prime[i]].begin(),g[prime[i]].end());
if(g[prime[i]].size()==n-1) ans=ans*qpow(prime[i],g[prime[i]][0]);
else ans=ans*qpow(prime[i],g[prime[i]][1]);
}
printf("%lld\n",ans);
return 0;
}
/**
3 4 4 4 2
**/
题目大意:
给定一个操作,可以使任意一个子区间的数变为该子区间的中位数,问可不可以使得序列最后都变为m
题目思路:
这题 ,emmm,太多的不应该,总结:不要思维僵化。
正题:
首先,这个题目考虑如何呢?
推论1:当有两个相同相连的数的时候,那么整个序列都可以变为相同的数,扩张即可。
1.所以首先思路考虑,只要找到一个区间,长度大于等于2,使得该区间的中位数为m,那么就肯定yes,因为长度大于等于2完全可以靠推论1进行扩张
2.然后就wa了,解释:
首先注意看题目,中位数取在了(x+1)/2,也就是说当区间长度为2时,只要有一个比他大的就可以。
所以我们在第一步上进行扩充:只要存在一长度大于等于2的区间,该区间的中位数>=m,并且此时序列中有m存在,那么一定可以。
3.接下来,因为条件放松了,那么判断也就放松了:
其余情况无需考虑,只需要判断最小的奇数与偶数区间即可。
/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(2)
#include
#include
#include
#include
#include
#include
#define debug(x) cout<<#x<<":"< pp;
const ll INF=1e17;
const int maxn=2e5+6;
const int mod=998244353;
const double eps=1e-3;
inline bool read(ll &num)
{char in;bool IsN=false;
in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
ll num[maxn];
int root[maxn],cnt=0;
ll a[maxn];
int main()
{
int T;scanf("%d",&T);
while(T--){
read(n);read(m);
int f=0,f1=0;
for(int i=1;i<=n;i++){
read(num[i]);
if(num[i]==m) f1=1;
}
for(int i=1;i<=n-2;i++){
if(num[i]>=m&&num[i+1]>=m) f=1;
if(num[i]>=m&&num[i+2]>=m) f=1;
}
if(!f1){
printf("no\n");
continue;
}
if(n==1){
printf("yes\n");
continue;
}
// printf("%d\n",f1);
if(num[n]>=m&&num[n-1]>=m) f=1;
if(f) printf("yes\n");
else printf("no\n");
}
return 0;
}
/**
2
4 3
3 1 2 3
**/
其实也可以检查一下,长度为3的区间只要存在大于等于m的数两个以上即可:
/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(2)
#include
#include
#include
#include
#include
#include
#define debug(x) cout<<#x<<":"< pp;
const ll INF=1e17;
const int maxn=2e5+6;
const int mod=998244353;
const double eps=1e-3;
inline bool read(ll &num)
{char in;bool IsN=false;
in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
ll num[maxn];
int root[maxn],cnt=0;
ll a[maxn];
ll pre[maxn];
int main()
{
int T;scanf("%d",&T);
while(T--){
read(n);read(m);
int f=0,f1=0;
for(int i=1;i<=n;i++){
read(num[i]);
if(num[i]==m) f1=1;
pre[i]=pre[i-1];
if(num[i]>=m) pre[i]++;
}
if(!f1){
printf("no\n");
continue;
}
if(n==1){
printf("yes\n");
continue;
}
if(n==2){
sort(num+1,num+1+n);
if(num[1]==m) printf("yes\n");
else printf("no\n");
continue;
}
for(int i=3;i<=n;i++)
if(pre[i]-pre[i-3]>=2) f=1;
if(f) printf("yes\n");
else printf("no\n");
}
return 0;
}
/**
2
4 3
3 1 2 3
**/