ABC 439题解
A:输入输出题
B
https://atcoder.jp/contests/abc439/tasks/abc439_b
问题陈述
给你一个正整数 \(N\) 。请判断 \(N\) 是否是一个快乐的数字。
快乐数是一个非负整数,在重复下面的运算一定次数后变成 \(1\) :
- 用十进制表示法中各数位的平方和所得到的整数替换它。
- 例如,对 \(2026\) 进行一次这样的运算后,它就变成了 \(2^2+0^2+2^2+6^2 = 4+0+4+36 = 44\) 。
思路:模拟
点击查看代码
void solution::solve()
{
int num;cin>>num;
vector<int> vis(2027,0);
while(1)
{
if(vis[num]) return cout<<"No"<<endl,void();
//如果出现过 则输出no
else vis[num]++;
string s=to_string(num);
int len=s.size();
int sum=0;
for(int i=0;i<len;i++)
{
int n1=s[i]-'0';
sum+=n1*n1;
}
if(sum==1) return cout<<"Yes"<<endl,void();
num=sum;
}
}
C
https://atcoder.jp/contests/abc439/tasks/abc439_c
问题陈述
满足以下条件的正整数 n 称为好整数:
- 恰好有一对整数 \((x,y)\) 满足 \(0 \lt x \lt y\) 和 \(x^2+y^2=n\) 的条件。
例如,当 \(n=2026\) 时,可以验证 \((x,y)=(1,45)\) 是满足 \(0 \lt x \lt y\) 和 \(x^2+y^2=n\) 的唯一一对整数。因此, \(2026\) 是一个好整数。
给你一个正整数 \(N\) 。请列举所有不超过 \(N\) 的好整数。
思路:枚举
点击查看代码
void solution::solve()
{
int n;cin>>n;
vector<int> arr,cnt(N+10,0);
for(int i=1;i<=N;i++)
{
for(int j=i+1;i*i+j*j<=N;j++)
{
int num=i*i+j*j;
cnt[num]++;
}
}
for(int i=1;i<=n;i++) if(cnt[i]==1) arr.push_back(i);
cout<<arr.size()<<endl;
for(auto x:arr) cout<<x<<" ";
cout<<endl;
}
反思:
赛时卡了,首先是对时间复杂度的计算还不熟练,之所以枚举不会超时是因为即使从1-N,后面的大部分都会被跳过。其次就是理解错题意orz...其实对于题目的特定要求应该记住的,这里的“唯一”就被忽视了,导致浪费了大量时间。
D
问题陈述
给你一个长度为 \(N\) 的整数序列 A1-An 。
求满足以下所有条件的整数三元组 \((i,j,k)\) 的个数:
- \(1 \le i,j,k \le N\)
- \(Ai : Aj : Ak = 7:5:3\)
- \(\min(i,j,k) = j\) 或 \(\max(i,j,k) = j\) .
思路:
既然j是作为最大或者最小的索引,那么就记录前缀和后缀中符合条件的i和k。类似组合数学吧,但是感觉有点花太多时间写代码了...orz
点击查看代码
void solution::solve()
{
int n;cin>>n;
vector<int> a(n+1,0);
for(int i=1;i<=n;i++) cin>>a[i];
map<int,array<int,3>> hash,hash1;
int ans=0;
for(int i=1;i<=n;i++)
{
if(a[i]%3==0) hash[a[i]/3][0]++;
if(a[i]%7==0) hash[a[i]/7][1]++;
if(a[i]%5==0)
{
int pos=a[i]/5;
int s0=hash[pos][0],s1=hash[pos][1];
ans+=s0*s1;
//前缀所有满足条件的
}
}
for(int i=n;i>=1;i--)
{
if(a[i]%3==0) hash1[a[i]/3][0]++;
if(a[i]%7==0) hash1[a[i]/7][1]++;
if(a[i]%5==0)
{
int pos=a[i]/5;
int s0=hash1[pos][0],s1=hash1[pos][1];
ans+=s0*s1;
//后缀所有满足条件的
}
}
cout<<ans<<endl;
}
E
https://atcoder.jp/contests/abc439/tasks/abc439_e
问题陈述
编号为 \(1\) 至 \(N\) 的 \(N\) 人正在河边放风筝。
面向河岸的河水呈直线流淌,因此从现在开始,我们考虑一个二维坐标系, \(x\) /轴为河水方向, \(y\) /轴为高度方向。
人 \(i\) 站在 \((Ai, 0)\) 点,试图在 \((Bi, 1)\) 点放风筝。
但是,为了避免人与风筝发生碰撞,也为了避免风筝线缠绕在一起,如果满足以下条件, \(i\) 和 \(j\) ( \(i \neq j\) )就不能同时放风筝:
- 连接 \((Ai, 0)\) 和 \((Bi, 1)\) 的线段 "和 "连接 \((Aj, 0)\) 和 \((Bj, 1)\) 的线段 "有一个交点。(这包括线段的端点相互接触的情况)。
在遵守上述限制的前提下,最多可以同时放风筝的人数是多少?
思路:通过题目可以知道,目标的集合只要符合“不存在交叉”,也就是说,在a符合递增的情况下,只要b也符合递增,就必然符合题目要求。因此求的是最长递增子序列。
点击查看代码
void solution::solve()
{
int n;cin>>n;
vector<vector<int>> a(n,vector<int>(2));
for(int i=0;i<n;i++) cin>>a[i][0]>>a[i][1];
auto cmp=[&](vi &v1,vi &v2)
{
if(v1[0]==v2[0]) return v1[1]>v2[1];
return v1[0]<v2[0];
};
sort(a.begin(),a.end(),cmp);
//按照ai升序 如果ai相同则bi降序
vector<int> dp;
for(int i=0;i<n;i++)
{
//因为ai已经排序 所以只需要考虑bi
auto it=lower_bound(dp.begin(),dp.end(),a[i][1])-dp.begin();
if(it==dp.size()) dp.push_back(a[i][1]);
else dp[it]=a[i][1];
}
//求最长递增子序列长度
cout<<dp.size();
}
F
https://atcoder.jp/contests/abc439/tasks/abc439_f
问题陈述
长度为 \(k\) 的序列 \(a=(a1,a2,\dots,ak)\) 被定义为角松样如下:
序列中的峰值的点的个数大于谷值点的个数。
给你一个 \((1,2,\dots,N)\) 的排列组合 \(P\) 。
求在 \(998244353\) 的模中, \(P\) 的(不一定连续的)子序列中类似于角松的序列的个数。
由于渲染问题所以是我稍微概括的题意,如果不大明白的话可以跳转链接看原题。
思路:
当且仅当开头结尾都是峰值的时候,峰值的点的个数必然严格大于谷值。
也就是(a2>a1&&ak-1>ak)
记录下bg(i前面比pi小的值的个数)ed(i后面比pi小的值的个数)
在这样的条件下,首先单独计算只含有三个数的时候 也就是res=sum(bg[i] * ed[i])
然后再记录四个以上的情况 也就是bg[l] * 2^(r-l+1) * ed[r]
代码中用s来记录了bg[l] * 2^(r-l+1)
(此处应该有图 但是我没找到手机 所以没有了)
点击查看代码
void solution::solve()
{
int n;cin>>n;
vector<int> p(n);
for(int i=0;i<n;i++) cin>>p[i];
SegmentTree<int> tb(n),te(n);
vector<int> bg(n+1,0),ed(n+1,0);
//记录pi前小于pi的个数 pi后小于pi的个数
for(int i=0;i<n;i++)
{
bg[i]=tb.rangeQuery(0,p[i]);
tb.modify(p[i],1);
}
for(int i=n-1;i>=0;i--)
{
ed[i]=te.rangeQuery(0,p[i]);
te.modify(p[i],1);
}
int res=0;
for(int i=0;i<n;i++) res=(res+bg[i]*ed[i]%mod)%mod;
int s=0;
for(int i=0;i<n;i++)
{
res=(res+s*ed[i]%mod)%mod;
s=(2*s%mod+bg[i])%mod;
}
//计算累计的2^(r-l-1)
cout<<res<<endl;
}
有诸多参考官方题解的部分,还需多加练习TT
另:写这么多题太费时间了,下次从d开始写题解

浙公网安备 33010602011771号