Codeforces Round #722 (Div. 2)
作者:互联网
文章目录
- 比赛链接
- Problem A:[Eshag Loves Big Arrays](https://codeforces.ml/contest/1529/problem/A)
- Problem B:[Sifid and Strange Subsequences](https://codeforces.ml/contest/1529/problem/B)
- Problem C:[Parsa's Humongous Tree](https://codeforces.ml/contest/1529/problem/C)
- Problem D:[Kavi on Pairing Duty](https://codeforces.ml/contest/1529/problem/D)
比赛链接
Problem A:Eshag Loves Big Arrays
给 你 n 个 数 的 数 组 a , 对 于 a 的 任 意 序 列 , 我 们 可 以 把 该 序 列 中 严 格 大 于 该 序 列 A V G ( 平 均 值 ) 的 数 字 删 除 , 问 最 多 能 删 除 多 少 个 数 字 。 思 路 : 要 想 删 除 多 的 数 字 , 最 好 就 是 让 最 小 的 逐 个 去 和 最 大 的 数 字 去 匹 配 , 模 拟 就 好 了 给你n个数的数组a,对于a的任意序列,我们可以把该序列中严格大于该序列AVG(平均值)的数字删除,\\ 问最多能删除多少个数字。\\ 思路:要想删除多的数字,最好就是让最小的逐个去和最大的数字去匹配,模拟就好了 给你n个数的数组a,对于a的任意序列,我们可以把该序列中严格大于该序列AVG(平均值)的数字删除,问最多能删除多少个数字。思路:要想删除多的数字,最好就是让最小的逐个去和最大的数字去匹配,模拟就好了
// Problem: A. Eshag Loves Big Arrays
// Contest: Codeforces - Codeforces Round #722 (Div. 2)
// URL: https://codeforces.com/contest/1529/problem/0
// Memory Limit: 256 MB
// Time Limit: 1000 ms
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <queue>
#include <set>
#include <map>
#include <vector>
#define pb push_back
#define in insert
#define mem(f, x) memset(f,x,sizeof(f))
#define fo(i,a,n) for(int i=(a);i<=(n);++i)
#define fo_(i,a,n) for(int i=(a);i<(n);++i)
#define debug(x) cout<<#x<<":"<<x<<endl;
#define endl '\n'
using namespace std;
template<typename T>
ostream& operator<<(ostream& os,const vector<T>&v){for(int i=0,j=0;i<v.size();i++,j++)if(j>=5){j=0;puts("");}else os<<v[i]<<" ";return os;}
template<typename T>
ostream& operator<<(ostream& os,const set<T>&v){for(auto c:v)os<<c<<" ";return os;}
typedef pair<int,int>PII;
typedef pair<long,long>PLL;
typedef long long ll;
typedef unsigned long long ull;
const int N=2e5+10,M=1e9+7;
ll n,m,_;
void solve()
{
cin>>n;
double a[110];
fo(i,1,n)cin>>a[i];
sort(a+1,a+n+1);
int res=0;
double aver=a[1];
for(int i=n;i>=2;i--)
{
aver+=a[i];
if(aver/2<a[i])res++;
aver-=a[i];
}
cout<<res<<endl;
}
int main()
{
cin>>_;
while(_--)
{
solve();
}
return 0;
}
Problem B:Sifid and Strange Subsequences
非 常 唬 人 的 一 道 题 , 一 开 始 没 人 过 就 离 谱 , 以 为 是 d p , 后 来 画 了 画 , 就 是 贪 心 , 但 是 没 有 注 意 到 特 殊 情 况 ( 就 是 考 虑 的 有 问 题 ) , 一 直 w a 非常唬人的一道题,一开始没人过就离谱,以为是dp,后来画了画,就是贪心,但是没有注意到特殊\\情况(就是考虑的有问题),一直wa 非常唬人的一道题,一开始没人过就离谱,以为是dp,后来画了画,就是贪心,但是没有注意到特殊情况(就是考虑的有问题),一直wa
给 定 n 个 数 的 数 组 a , 求 出 a 中 最 长 的 s t r a n g e 数 组 的 长 度 是 多 少 我 们 定 义 ( b 1 , b 2 , . . . , b k ) 是 s t r a n g e 的 当 对 于 数 组 中 的 任 意 p a i r ( i , j ) , 1 < = i < = j < = k , ∣ a i − a j ∣ > = M A X ( M A X 是 序 列 中 元 素 的 最 大 值 ) , 定 义 1 个 数 是 s t r a n g e 的 给定n个数的数组a,求出a中最长的strange数组的长度是多少\\ 我们定义(b_1,b_2,...,b_k)是strange的\\当对于数组中的任意pair(i,j),1<=i<=j<=k,|a_i-a_j| >=MAX(MAX是序列中元素的最大值),定义1个数是strange的 给定n个数的数组a,求出a中最长的strange数组的长度是多少我们定义(b1,b2,...,bk)是strange的当对于数组中的任意pair(i,j),1<=i<=j<=k,∣ai−aj∣>=MAX(MAX是序列中元素的最大值),定义1个数是strange的
容 易 发 现 负 数 和 0 是 都 可 以 要 的 , 想 到 先 进 行 排 序 , 容 易 发 现 a [ j ] − a [ i ] 是 递 增 的 , 我 们 只 需 要 判 断 a [ j ] − a [ i ] > = m a x 即 可 , 也 容 易 得 到 最 多 只 有 一 个 正 数 , 累 加 答 案 即 可 容易发现负数和0是都可以要的,想到先进行排序,容易发现a[j]-a[i]是递增的,我们只需要\\ 判断a[j]-a[i]>=max即可,也容易得到最多只有一个正数,累加答案即可 容易发现负数和0是都可以要的,想到先进行排序,容易发现a[j]−a[i]是递增的,我们只需要判断a[j]−a[i]>=max即可,也容易得到最多只有一个正数,累加答案即可
1
4
-300 -1 0 2
ans=3
按照思路重新打的,话说md里边也有自动换行,不错啊
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+10;
const int M=1e9+10;
int t,n,a[N];
int minn;
void solve()
{
cin>>n;
minn=2*M;
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
sort(a+1,a+n+1);
int res=1;
for(int i=2;i<=n;i++)
{
minn=min(minn,a[i]-a[i-1]);
if(minn>=a[i])
{
res++;
}
else break;
}
cout<<res<<endl;
}
int main()
{
cin>>t;
while(t--)
solve();
return 0;
}
Problem C:Parsa’s Humongous Tree
给 你 n 个 节 点 的 一 棵 树 , 树 中 节 点 从 1 n 编 号 , 无 根 树 , 每 个 节 点 都 有 一 个 l v , r v , 节 点 的 权 值 a v l v < = a v < = r v , 对 于 ( u , v ) 的 一 条 路 径 , 让 ∑ ∣ a u − a v ∣ 值 最 大 , 求 最 大 值 给你n个节点的一棵树,树中节点从1~n编号,无根树,每个节点都有一个l_v,r_v,节点的权值a_v\\l_v<=a_v<=r_v,对于(u,v)的一条路径,让\sum|a_u-a_v|值最大,求最大值 给你n个节点的一棵树,树中节点从1 n编号,无根树,每个节点都有一个lv,rv,节点的权值avlv<=av<=rv,对于(u,v)的一条路径,让∑∣au−av∣值最大,求最大值
250 组 测 试 样 例 , n < = 1 0 5 , ( 1 < = l i < = r i < = 1 0 9 ) , 说 实 话 想 不 到 怎 么 写 , 现 在 学 到 了 , 以 前 还 是 写 过 树 形 d p 的 , 但 是 这 题 不 会 就 代 表 学 的 有 问 题 , 或 者 不 会 处 理 有 很 多 人 都 过 的 题 , 既 然 这 题 很 多 人 都 过 了 ( d i v 2 的 话 1000 人 以 上 的 题 都 算 是 很 多 人 都 会 的 题 了 ) , 那 么 肯 定 不 是 非 常 难 的 题 当 然 可 能 思 路 很 难 想 250组测试样例,n<=10^5,(1<=l_i<=r_i<=10^9),说实话想不到怎么写,现在学到了,以前\\还是写过树形dp的,但是这题不会就代表学的有问题,或者不会处理有很多人都过的题,既然这题\\很多人都过了(div2的话1000人以上的题都算是很多人都会的题了),那么肯定不是非常难的题\\当然可能思路很难想 250组测试样例,n<=105,(1<=li<=ri<=109),说实话想不到怎么写,现在学到了,以前还是写过树形dp的,但是这题不会就代表学的有问题,或者不会处理有很多人都过的题,既然这题很多人都过了(div2的话1000人以上的题都算是很多人都会的题了),那么肯定不是非常难的题当然可能思路很难想
注 意 到 如 果 每 个 点 的 权 值 都 去 临 界 的 话 , 那 么 绝 对 值 的 差 是 最 大 的 , 问 题 就 是 对 于 每 个 点 我 们 取 左 边 界 还 是 右 边 界 , 树 形 d p 即 可 注意到如果每个点的权值都去临界的话,那么绝对值的差是最大的,问题就是对于每个点我们取左边界\\还是右边界,树形dp即可 注意到如果每个点的权值都去临界的话,那么绝对值的差是最大的,问题就是对于每个点我们取左边界还是右边界,树形dp即可
// Problem: C. Parsa's Humongous Tree
// Contest: Codeforces - Codeforces Round #722 (Div. 2)
// URL: https://codeforces.ml/contest/1529/problem/C
// Memory Limit: 256 MB
// Time Limit: 1000 ms
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <queue>
#include <set>
#include <map>
#include <vector>
#define pb push_back
#define in insert
#define mem(f, x) memset(f,x,sizeof(f))
#define fo(i,a,n) for(int i=(a);i<=(n);++i)
#define fo_(i,a,n) for(int i=(a);i<(n);++i)
#define debug(x) cout<<#x<<":"<<x<<endl;
#define endl '\n'
using namespace std;
template<typename T>
ostream& operator<<(ostream& os,const vector<T>&v){for(int i=0,j=0;i<v.size();i++,j++)if(j>=5){j=0;puts("");}else os<<v[i]<<" ";return os;}
template<typename T>
ostream& operator<<(ostream& os,const set<T>&v){for(auto c:v)os<<c<<" ";return os;}
typedef pair<int,int>PII;
typedef pair<long,long>PLL;
typedef long long ll;
typedef unsigned long long ull;
const int N=1e5+10,M=1e9+7;
ll n,m,_;
int l[N],r[N];
int dp[N][2];
vector<int>adj[N];
void init()
{
fo(i,1,n)dp[i][0]=dp[i][1]=0,adj[i].clear();
}
void dfs(int u,int fa)
{
for(int i=0;i<adj[u].size();i++)
{
int j=adj[u][i];//临界点
if(j==fa)continue;
dfs(j,u);//得到了dp[j][0],dp[j][1],求dp[u];
dp[u][0]+=max(dp[j][0]+abs(l[u]-l[j]),dp[j][1]+abs(l[u]-r[j]));
dp[u][1]+=max(dp[j][0]+abs(r[u]-l[j]),dp[j][1]+abs(r[u]-r[j]));
}
}
void solve()
{
cin>>n;
init();
fo(i,1,n)scanf("%d%d",&l[i],&r[i]);
n--;
while(n--){
int u,v;scanf("%d%d",&u,&v);
adj[u].pb(v);
adj[v].pb(u);
}
dfs(1,0);
cout<<max(dp[1][0],dp[1][1])<<endl;
}
int main()
{
cin>>_;
while(_--)
{
solve();
}
return 0;
}
Problem D:Kavi on Pairing Duty
对 于 2 ∗ n 个 在 数 轴 1 ∼ 2 ∗ n 的 数 , 对 他 们 进 行 配 对 , 如 果 两 个 线 段 A 、 B 有 1. A 被 B 或 B 被 A 完 全 覆 盖 2. A 和 B 有 相 同 的 长 度 , 那 么 认 为 他 们 是 合 法 的 求 合 法 的 方 案 对 998244353 取 模 对于2*n个在数轴1 \sim 2*n的数,对他们进行配对,如果两个线段A、B有\\ 1.A被B或B被A完全覆盖 2.A和B有相同的长度,那么认为他们是合法的\\求合法的方案对998244353取模 对于2∗n个在数轴1∼2∗n的数,对他们进行配对,如果两个线段A、B有1.A被B或B被A完全覆盖2.A和B有相同的长度,那么认为他们是合法的求合法的方案对998244353取模
确 实 是 d p + 数 学 , 考 虑 已 经 知 道 了 d p [ 1 ] , d p [ 2 ] , d p [ 3 ] , 求 d p [ 4 ] , 通 过 画 图 , 首 先 是 将 n = = 4 时 把 1 和 n 用 一 个 线 段 覆 盖 , 那 么 转 换 成 了 d p [ 3 ] , 同 理 还 有 d p [ 2 ] , d p [ 1 ] , d p [ 0 ] , 最 后 考 虑 将 1 n 覆 盖 此 时 的 方 案 数 是 n 的 非 1 的 因 子 数 , 使 用 一 个 s u m 前 缀 和 数 组 处 理 即 可 , 画 图 好 理 解 确实是dp+数学,考虑已经知道了dp[1],dp[2],dp[3],求dp[4],通过画图,首先是将n==4时\\ 把1和n用一个线段覆盖,那么转换成了dp[3],同理还有dp[2],dp[1],dp[0],最后考虑将1~n覆盖\\此时的方案数是n的非1的因子数,使用一个sum前缀和数组处理即可,画图好理解 确实是dp+数学,考虑已经知道了dp[1],dp[2],dp[3],求dp[4],通过画图,首先是将n==4时把1和n用一个线段覆盖,那么转换成了dp[3],同理还有dp[2],dp[1],dp[0],最后考虑将1 n覆盖此时的方案数是n的非1的因子数,使用一个sum前缀和数组处理即可,画图好理解
在N*(ln(sqrt(N)))中求1~N的所有数的因数
void get()
{// 得到n的非1的约数个数 4 ==2 4 ==2
for(int i=1;i*i<N;i++)//约数总是从对存在的
{//枚举第一个约数
for(int j=i;i*j<N;j++)//因为i是从小到大枚举的,j是枚举的另一个约数
{
// num[i*j]++;
num[i*j]+=2;//假设i和j是两个不同的约数,num++
if(i==j)num[i*j]--;//如果是两个相同的约数num--;
}
}
for(int i=1;i<N;i++)
num[i]--;
}
如何求N的所有因子呢?
(基础课的题)
容易知道约数是成对的,除非完全平方数,扫描d=1~sqrt(N),若d能整除,N/d也能整除
时间复杂度是O(sqrt(N))
int fa[1600],m=0;
for(int i=1;i*i<=n;i++){
if(n%i==0)
fa[++m]=i;
if(i!=n/i)fa[++m]=n/i;
}
for(int i=1;i<=m;i++)cout<<fa[i]<<" ";
// Problem: D. Kavi on Pairing Duty
// Contest: Codeforces - Codeforces Round #722 (Div. 2)
// URL: https://codeforces.com/contest/1529/problem/D
// Memory Limit: 256 MB
// Time Limit: 1000 ms
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <queue>
#include <set>
#include <map>
#include <vector>
#define pb push_back
#define in insert
#define mem(f, x) memset(f,x,sizeof(f))
#define fo(i,a,n) for(int i=(a);i<=(n);++i)
#define fo_(i,a,n) for(int i=(a);i<(n);++i)
#define debug(x) cout<<#x<<":"<<x<<endl;
#define endl '\n'
using namespace std;
template<typename T>
ostream& operator<<(ostream& os,const vector<T>&v){for(int i=0,j=0;i<v.size();i++,j++)if(j>=5){j=0;puts("");}else os<<v[i]<<" ";return os;}
template<typename T>
ostream& operator<<(ostream& os,const set<T>&v){for(auto c:v)os<<c<<" ";return os;}
typedef pair<int,int>PII;
typedef pair<long,long>PLL;
typedef long long ll;
typedef unsigned long long ull;
const int N=1e6+10,mod=998244353;
ll n,m,_;
int dp[N];
int num[N];
int f[N];
void get()
{// 得到n的非1的约数个数 4 ==2 4 ==2
for(int i=1;i*i<N;i++)//约数总是从对存在的
{//枚举第一个约数
for(int j=i;i*j<N;j++)//因为i是从小到大枚举的,j是枚举的另一个约数
{
// num[i*j]++;
num[i*j]+=2;//假设i和j是两个不同的约数,num++
if(i==j)num[i*j]--;//如果是两个相同的约数num--;
}
}
for(int i=1;i<N;i++)
num[i]--;
}
void solve()
{
get();
dp[0]=1;//前缀和
// dp[1]=2;
// f[1]=1;
// for(int i=1;i<=100;++i)
// cout<<i<<" "<<num[i]<<endl;
//dp[1]=dp[0]+get(1);
//dp[2]=dp[1]+dp[0]+get(2)=1+1+1==3
//dp[3]=dp[2]+dp[1]+dp[0]+get(3);
//dp[4]=dp[3]+dp[2]+dp[1]+dp[0]+get(4);
//dp[i]表示dp数组的前缀和,不算num
for(int i=1;i<=n;i++)
{
f[i]=(dp[i-1]+num[i])%mod;
dp[i]=(dp[i-1]+f[i])%mod;
}
cout<<f[n]<<endl;
}
int main()
{
cin>>n;solve();
return 0;
}
标签:int,Codeforces,long,num,722,Div,include,dp,define 来源: https://blog.csdn.net/hacker__man/article/details/117266803