当前位置:网站首页>AtCoder Beginner Contest 262 部分题解
AtCoder Beginner Contest 262 部分题解
2022-08-04 16:33:00 【山中一扶苏】
本篇题解只是记录我的做题过程代码,不提供最优解
(另外这里所有的时间复杂度都只分析单个样例,不算 t t t的时间复杂度)
A
点击此处查看对应的题目.
本题设计算法:模拟
直接从n向后找到 除以4余数为2的数 即可
时间复杂度 O ( 1 ) O(1) O(1)
#include <iostream>
#include <cstring>
#include <algorithm>
#include <ctime>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 2e5 + 10;
int main()
{
int n;
cin >> n;
for (int i = n;i <= 4000;i ++) {
if (i % 4 == 2) {
cout << i << '\n';
break;
}
}
return 0;
}
B
点击此处查看对应的题目.
本题设计算法:模拟
用邻接矩阵存图,枚举图上不同的三个点,判断是否三个点之间是否都有一条边即可
时间复杂度 O ( n 3 ) O(n ^ 3) O(n3)
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1010;
int g[N][N];
ll res;
int main()
{
int n,m;
cin >> n >> m;
while(m -- ) {
int a,b;
cin >> a >> b;
g[a][b] = 1,g[b][a] = 1;
}
for (int i = 1;i <= n - 2;i ++ ) {
for (int j = i + 1;j <= n - 1;j ++ ) {
for (int k = j + 1;k <= n;k ++ ) {
if (g[i][j] && g[j][k] && g[i][k]) res ++;
}
}
}
cout << res << '\n';
return 0;
}
C
点击此处查看对应的题目.
本题设计算法:组合数 + 数组映射
题目要求 m i n ( a [ i ] , a [ j ] ) = i , m a x ( a [ i ] , a [ j ] ) = j , 0 < i < j < = N min(a[i],a[j]) = i,max(a[i],a[j]) = j,0 < i < j <= N min(a[i],a[j])=i,max(a[i],a[j])=j,0<i<j<=N,又由于a数组是1-i的整数。
所以相当于就是要令 a[a[i]] = i;另外当 a[i] == i 的情况下,则可以自由 C x 2 C_x^2 Cx2 组合答案 (我这里由于1-n前缀和也可表示就直接用前缀和表示了)。
时间复杂度 O ( n ) O(n) O(n)
#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
#include <map>
#include <set>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> PII;
const int N = 5e5 + 10;
ll a[N],k[N],sum[N];
vector<ll> g[N];
int main()
{
int n;
cin >> n;
for (int i = 1;i <= n;i ++ ) {
scanf("%lld",&a[i]);
k[i] = i;
sum[i] = sum[i - 1] + k[i];
}
ll res = 0,x = 0;
for (ll i = 1;i <= n;i ++ ) {
if (a[i] == i) x ++;
else res += (a[a[i]] == i);
}
res = res / 2 + sum[x - 1];
cout << res << '\n';
return 0;
}
D
点击此处查看对应的题目.
本题设计算法:动态规划 + 取模状态转移
首先我们先想状态表示:
我们最理想的情况当然是设 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k] 为前 i 个元素中, 选择了 j 个元素, 此时所有元素的和为 k 的方案数, 但是看到了大小范围, 发现这样做行不通.
根据题目的意思,我们可以重设状态表示,设 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k] 为前 i 个元素中, 选择了 j 个元素, 此时所有元素的和为 % j 为 k 的方案数。
所以不选的状态转移大致就可以是这样: d p [ i ] [ j ] [ k ] = d p [ i − 1 ] [ j ] [ k ] dp[i][j][k] = dp[i - 1][j][k] dp[i][j][k]=dp[i−1][j][k]
但是如果选择的话,我们就要考虑k的转移,也就是我们已知 sum % j = k ,如何求得 (sum - a[j])%(j-1) = ?
简单推一下式子就发现,这并不好求,我们需要改变状态转移方程了
简单回想起来,我们发现上一次之所以失败,是因为我们对于k转移的时候,模数改变,导致无法推导出来转移,我们吸取教训,考虑如果模数不变,枚举一下模数,也就是枚举一下子集大小,来转移
dp[j][k][l]表示,前j个数中,选择了k个数,并且和 %i 为 l 的方案数
我们进一步发现,%i意味着算数平均值除以i,意味着我们选择了 i 个数,也就是我们循环k的上限应该为i
这样的话,我们因为模数固定,状态转移变得容易了起来
大致就是:
不选 a[j]: dp[j][k][l] += dp[j - 1][k][l]
选 a[j]: dp[j][k][l] += dp[j - 1][k - 1][l - a[j] % i]
时间复杂度 O ( n 4 ) O(n^4) O(n4)
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
const ll N = 110,mod = 998244353;
ll a[N],dp[N][N][N];//为前i个元素中, 选择了j个元素, 此时元素的和%j为k的方案数
ll res;
int main()
{
int n;
cin >> n;
for (int i = 0;i < n;i ++ ) cin >> a[i];
for (int i = 1;i <= n;i ++ ) {//枚举所有选择i项的可能
memset(dp,0,sizeof dp);
dp[0][0][0] = 1;
for (int j = 0;j < n;j ++ ) {//枚举前j个数
for (int k = 0;k <= i;k ++ ) {//枚举已经选择的个数
for (int l = 0;l < i;l ++ ) {//枚举取模后的和
dp[j + 1][k][l] = (dp[j + 1][k][l] + dp[j][k][l]) % mod;
if (k < i) dp[j + 1][k + 1][(l + a[j]) % i] = (dp[j + 1][k + 1][(l + a[j]) % i] + dp[j][k][l]) % mod;
}
}
}
res = (res + dp[n][i][0]) % mod;
}
cout << res << '\n';
return 0;
}
E
点击此处查看对应的题目.
本题设计算法:逆元求组合数
本题要将n个点中将K个点染成红色,不同颜色的边的数量必须为偶数
这题我们可以从点的度数下手,设 s 为图中红色点的度数之和,r 为两个红色点的连接的边的数目的,d 为连接不同颜色点的边的数目,于是我们可以成立这样一个公式:s = 2 *r + d。
由于题目给出 d 是偶数,2 * r 必然是偶数,所以红色点的度数之和也必然是偶数
所以我们只要求出所有偶数度数点中红色的点的组合关系和在奇数度数点中红色点的组合关系,最后与之相乘即可。
另外,这里的求组合数的求法因为涉及取模,所以应用到 逆元求组合数
时间复杂度 O ( N l o g ( m o d − 2 ) ) O(Nlog(mod - 2)) O(Nlog(mod−2))
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10,mod = 998244353;
ll a[N],d[N],fact[N], infact[N];
ll C(ll a,ll b) {return (fact[a] * infact[b] % mod * infact[a - b] % mod);}
int qmi(int a, int k, int p)
{
int res = 1;
while (k)
{
if (k & 1) res = (ll)res * a % p;
a = (ll)a * a % p;
k >>= 1;
}
return res;
}
void init()
{
fact[0] = infact[0] = 1;
for (int i = 1; i < N; i ++ )
{
fact[i] = (ll)fact[i - 1] * i % mod;
infact[i] = (ll)infact[i - 1] * qmi(i, mod - 2, mod) % mod;
}
}
int main()
{
ll n,m,k;
init();
cin >> n >> m >> k;
while (m -- ) {
int a,b;
cin >> a >> b;
d[a] ++,d[b] ++;
}
ll odd = 0;
for (int i = 1;i <= n;i ++ )
if (d[i] & 1)
odd ++;
ll res = 0;
for (ll i = 0;i <= k;i += 2){//在k个红色点中枚举i个奇度数点
if (i <= odd && k - i <= n - odd) {
res = (res + (C(odd,i) * C(n - odd,k - i)) % mod) % mod;
}
}
cout << res << '\n';
return 0;
}
边栏推荐
- 动手学深度学习_AlexNet
- NFT blind box mining system dapp development NFT chain game construction
- leetcode 48. Rotate Image 旋转图像(Medium)
- Taurus.MVC WebAPI 入门开发教程2:添加控制器输出Hello World。
- 寻找消失的类名
- 推荐 7 月份 yyds 的开源项目
- 实践:二进制数据处理与封装
- HCIP笔记(6)
- 浙江移动咪咕MGV2000-K4_ZJ_S905l2_7661_线刷固件包
- Hubei Telecom Tianyi TY1608_S905L3B_MT7668_ card brush firmware package
猜你喜欢

湖北移动中兴B860AV2.1_S905L_线刷固件包

功率放大器的设计要点

No server is required, teach you to get real-time health code recognition with only 30 lines of code

07-输入输出系统

手把手教你搭建一个Minecraft 服务器

越来越火的图数据库到底能做什么?

Minecraft HMCL 使用认证服务器LittleSkin进行登录

工龄10年的测试员从大厂“裸辞”后...

跨链桥已成行业最大安全隐患 为什么和怎么办

从正负样本解耦看对比学习为何需要large batch size训练Ddcoupled Contrastive learning (DCT)
随机推荐
Does DMS have an interface to get the list of databases under each instance?
Analysis of Http-Sumggling Cache Vulnerability
开源一夏 | 请你谈谈网站是如何进行访问的?【web领域面试题】
【JVM】JVM调优
葫芦娃解析
云存储硬核技术内幕——(9) 相见时难别亦难
什么是会话劫持攻击以及如何防止会话劫持
redis
浙江移动咪咕MGV2000-K4_ZJ_S905l2_7661_线刷固件包
codeforces:808D. Array Division【二分 + 找规律】
测试零基础如何进入大厂?一场面试教会你(附面试题解析)
张乐:研发效能的黄金三角及需求与敏捷协作领域的实践|直播回顾
Mysql Explain
Go语言gin框架返回json格式里,怎么把某个int属性转成string返回?
广东移动魔百盒M411A _905L3_线刷固件包
博云入选Gartner中国云原生领域代表性厂商
历史上的今天:微软研究院的创始人诞生;陌陌正式上线;苹果发布 Newton OS
js判断一个对象是否在一个对象数组中
Win10 无线网卡驱动感叹号,显示错误代码56
Minecraft 服务器安装Forge 并添加Mod