2022/7/22 训练日志
Posted 钟钟终
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2022/7/22 训练日志相关的知识,希望对你有一定的参考价值。
思维训练
D1. Chopping Carrots (Easy Version)
题意:给定一个数组a[n],构造一个数组p[n],使得Max(a[i]/p[i])-Min(a[i]/p[i])
值最大。n的数据范围到3000.要求算式答案最小。
思路:
1.首先最容易想到要确定p数组的值,但这思路并不正确,首先会导致复杂度过大。
2.仔细观察算式,相除最大值无法确定,但最小值确存在范围1~a[1]
(数组大小为升序排列)
3.若枚举最小值后,下一步确定最大值,p[i]的值存在限制,必须要<=k,再比较找出一个算式答案最小。
#include <bits/stdc++.h>
//#define int long long
#define endl '\\n'
using namespace std;
const int N=1e6+100;
int n,k,a[N];
signed main()
int t;cin>>t;
while(t--)
cin>>n>>k;
for(int i=1;i<=n;i++)
cin>>a[i];
int ans=1e9,g=a[1];
for(int i=1;i<=g;i++)
int res=0;
for(int j=1;j<=n;j++)
int x=a[j]/i;
if(x>k) x=k;
res=max(res,a[j]/x);
ans=min(ans,res-i);
cout<<ans<<endl;
return 0;
C1. k-LCM (easy version)
本题为C2的简化版,k恒等于3。因此表明要围绕n/2进行分类讨论。
#include <bits/stdc++.h>
//#define int long long
#define endl '\\n'
using namespace std;
const int N=1e6+100;
int n,k;
signed main()
int t;cin>>t;
while(t--)
cin>>n>>k;
int g=n/2;
if(n%2)
cout<<1<<" "<<g<<" "<<g<<endl;
else
if(g%2)
cout<<2<<" "<<g-1<<" "<<g-1<<endl;
else
cout<<g<<" "<<g/2<<" "<<g/2<<endl;
return 0;
每日一题
C2. k-LCM (hard version)
在C1的基础上,将输出k-3个1,再将n-=(k-3)
,此时有三个数来构成n,题目便变化成了C1
#include <bits/stdc++.h>
//#define int long long
#define endl '\\n'
using namespace std;
const int N=1e6+100;
int n,k;
signed main()
int t;cin>>t;
while(t--)
cin>>n>>k;
for(int i=1;i<=k-3;i++)
cout<<1<<" ";
n-=(k-3);
int g=n/2;
if(n%2)
cout<<1<<" "<<g<<" "<<g<<endl;
else
if(g%2)
cout<<2<<" "<<g-1<<" "<<g-1<<endl;
else
cout<<g<<" "<<g/2<<" "<<g/2<<endl;
return 0;
算法训练
P1137 旅行计划
一道经典得拓扑排序题,
思路:
1.一张有向无环图的拓扑序可以使得任意的起点u,它的一个终点v,在序列中的顺序是u在前v在后
2.把入度为0的点入队,并加入拓扑序。之后断掉以这个点为起点的边,即将这些边的终点的入度减一,直到队为空就好。
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
int n,m,indgr[maxn],city[maxn],head[maxn],cnt;
struct node
int to,nxt;
g[maxn];
queue<int>q;
void add_edge(int u,int v)
g[++cnt].to=v;
g[cnt].nxt=head[u];
head[u]=cnt;
void topsort()
for(int i=1;i<=n;i++)
if(indgr[i]==0)
city[i]=1;q.push(i);
while(!q.empty())
int k=q.front(); //取得入度为0的结点
q.pop();
for(int i=head[k];i;i=g[i].nxt) //i表示与邻接点相连的变
int v=g[i].to; //通过这个点找到的下一个点
indgr[v]--; //入度减去1
city[v]=max(city[v],city[k]+1); //dp思想
if(indgr[v]==0) //若为0加入队列
q.push(v);
int main()
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
head[i]=-1;city[i]=1;
for(int i=1;i<=m;i++)
int a,b;
scanf("%d%d",&a,&b);
add_edge(a,b);
indgr[b]++;
topsort();
for(int i=1;i<=n;i++)
cout<<city[i]<<endl;
return 0;
E. Qpwoeirut and Vertices
本题涉及知识较多,尚有ST表部分的应用没看懂,得抽个时间将ST表内容学下。
#include <bits/stdc++.h>
//#define int long long
#define endl '\\n'
using namespace std;
const int N=1e5+100;
int n,m,f[N],tol,val[N],lg[N];
vector<int>g[N];
bool vis[N];
//并查集模板
int r_find(int r)
if(r==f[r]) return f[r];
f[r]=r_find(f[r]);
return f[r];
//树链剖分模板
int son[N],siz[N],top[N],fa[N],dep[N];
void dfs1(int u,int pare) //重构树lca初始化
siz[u]=1;dep[u]=dep[pare]+1;
son[u]=0;fa[u]=pare;
for(auto &v:g[u])
if(v!=pare)
dfs1(v,u);
siz[u]+=siz[v];
if(siz[son[u]]<siz[v])
son[u]=v;
void dfs2(int u,int topf)
top[u]=topf;
if(son[u])
dfs2(son[u],topf);
for(auto &v:g[u])
if(v!=fa[u]&&v!=son[u])
dfs2(v,v);
//树剖求lca模板
int lca(int x,int y)
while(top[x]!=top[y])
if(dep[top[x]]<dep[top[y]])
swap(x,y);
x=fa[top[x]];
return dep[x]<dep[y]?x:y;
//kurskral重构树模板
void kruskal()
for(int i=1;i<n*2;i++)
f[i]=i;
tol=n;
for(int i=1;i<=m;i++)
int x,y;cin>>x>>y;
int fx=r_find(x),fy=r_find(y);
if(fx!=fy)
val[++tol]=i;
f[fx]=f[fy]=tol;
g[fx].push_back(tol),g[tol].push_back(fx);
g[fy].push_back(tol),g[tol].push_back(fy);
//ST表求区间最大值
void build()
//ST表查询区间极大值
void query()
signed main()
int t;cin>>t;
for(int i=1;i<=N;i++)
lg[i]=lg[i>>1]+1;
while(t--)
cin>>n>>m;
kruskal();
dfs1(tol,0);
dfs2(tol,tol);
int q;cin>>q;
while(q--)
int l,r;cin>>l>>r;
for(int i=1;i<=tol;i++)
g[i].clear(),sz[i]=top[i]=fa[i]=son[i]=dep[i]=0;
return 0;
以上是关于2022/7/22 训练日志的主要内容,如果未能解决你的问题,请参考以下文章