已经补AEFGK
E. Exam Results
枚举+二分+动态开点权值线段树
O
(
n
l
o
g
N
)
O(nlogN)
O(nlogN)
智商太低,想不到什么贪心只能暴力数据结构维护
对于所有学生的最高成绩只可能是 a i ( 1 ≤ i ≤ n ) a_i(1\leq i\leq n) ai(1≤i≤n)或者最大的 b i b_i bi,对于后面一种情况直接特殊考虑一下即可,下面主要分析最高成绩是 a i ( 1 ≤ i ≤ n ) a_i(1\leq i\leq n) ai(1≤i≤n)的情况。
首先将所有学生按照
a
a
a从大到小排序,然后依次枚举每一个学生的
a
i
a_i
ai作为最高成绩,假设当前这位是
a
i
a_i
ai,那么对于
i
→
n
i\to n
i→n这些学生的分数肯定越大越好即所有学生的成绩应该是
a
a
a,统计
i
→
n
i\to n
i→n满足题目意思的个数只需要二分一下即可。
而对于
1
→
i
−
1
1\to i-1
1→i−1这些学生,我们知道要保证当前
a
i
a_i
ai是最高成绩这些学生的分数一定不能是
a
a
a,只能是
b
b
b,因此每考虑一个学生后把当前学生的
b
b
b加入到动态开点权值线段树中,然后对于
1
→
i
−
1
1\to i-1
1→i−1这些学生只需要直接查询即可。
注意当前
a
i
a_i
ai不能作为最高分数的情况当且仅当权值线段树中的b的最大值大于
a
i
a_i
ai
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<random>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=1e9+7;
const int N=200010;
struct node1
{
int a,b;
}q[N];
bool cmp1(node1 &x,node1 &y)
{
if(x.a==y.a) return x.b<y.b;
return x.a>y.a;
}
bool cmp2(node1 &x,node1 &y)
{
if(x.b==y.b) return x.a>y.a;
return x.b>y.b;
}
int n,p;
struct node2
{
int l,r;
int sz;
}tree[N*40];
int root,cnt;
void insert(int &u,int l,int r,int pos)
{
if(!u) u=++cnt;
if(l==r)
{
tree[u].sz++;
return;
}
int mid=l+r>>1;
if(pos<=mid) insert(tree[u].l,l,mid,pos);
else insert(tree[u].r,mid+1,r,pos);
tree[u].sz=tree[tree[u].l].sz+tree[tree[u].r].sz;
}
int query(int u,int l,int r,int L,int R)
{
if(L>R) return 0;
if(!u) return 0;
if(l>=L&&r<=R) return tree[u].sz;
int mid=l+r>>1;
int v=0;
if(L<=mid) v+=query(tree[u].l,l,mid,L,R);
if(R>mid) v+=query(tree[u].r,mid+1,r,L,R);
return v;
}
void clear(int &u,int l,int r)
{
if(!u) return;
if(l==r)
{
tree[u].sz=0;
u=0;
return;
}
int mid=l+r>>1;
clear(tree[u].l,l,mid);
clear(tree[u].r,mid+1,r);
tree[u].sz=0;u=0;
}
int main()
{
IO;
int T=1;
cin>>T;
for(int ca=1;ca<=T;ca++)
{
cin>>n>>p;
for(int i=1;i<=n;i++)
cin>>q[i].a>>q[i].b;
int res=0;
sort(q+1,q+1+n,cmp1);
for(int i=1;i<=n;i++)
{
int fl=(1ll*q[i].a*p+99)/100;
if(query(root,1,1e9,q[i].a+1,1e9)>0)
{
insert(root,1,1e9,q[i].b);
continue;
}
int l=i,r=n;
while(l<r)
{
int mid=l+r+1>>1;
if(q[mid].a>=fl) l=mid;
else r=mid-1;
}
res=max(res,r-i+1+query(root,1,1e9,fl,q[i].a));
insert(root,1,1e9,q[i].b);
}
sort(q+1,q+1+n,cmp2);
int now=1,fl=(1ll*q[1].b*p+99)/100; //之前now=0一直wa,应该把now=1 少算了一个点
for(int i=2;i<=n;i++)
if(q[i].a>=fl&&q[i].a<=q[1].b||q[i].b>=fl) now++;
res=max(now,res);
printf("Case #%d: %d\n",ca,res);
clear(root,1,1e9);cnt=0;//清点
}
return 0;
}
F. Friendly Group
并查集维护一下连通性即可。
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
//#pragma GCC optimize(2)
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<random>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=1e9+7;
const int N=1000010;
int h[N],e[2*N],ne[2*N],idx;
int p[N];
int find(int x) {return x==p[x]?x:p[x]=find(p[x]);}
void add(int a,int b)
{
e[idx]=b;
ne[idx]=h[a];
h[a]=idx++;
}
pii edge[N];
bool st[N];
void dfs(int u,int fa)
{
st[u]=1;
for(int i=h[u];i!=-1;i=ne[i])
{
int j=e[i];
if(j==fa||st[j]) continue;
dfs(j,u);
}
}
int main()
{
IO;
int T=1;
cin>>T;
for(int ca=1;ca<=T;ca++)
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
p[i]=i;
st[i]=0;
h[i]=-1;
}
idx=0;
for(int i=1;i<=m;i++)
{
int a,b;
cin>>a>>b;
edge[i]={a,b};
add(a,b),add(b,a);
}
for(int i=1;i<=m;i++)
{
int a=edge[i].first,b=edge[i].second;
if(st[a]||st[b]) continue;
int pa=find(a),pb=find(b);
if(pa==pb)
dfs(a,-1);
else
p[pa]=pb;
}
int cnt=0;
for(int i=1;i<=n;i++) cnt-=st[i];
for(int i=1;i<=m;i++)
{
int a=edge[i].first,b=edge[i].second;
if(st[a]&&st[b]) cnt++;
}
printf("Case #%d: %d\n",ca,cnt);
}
return 0;
}
G. Good Number
按块考虑,数学题。
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
//#pragma GCC optimize(2)
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<random>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=1e9+7;
const int N=200010;
int n;
int main()
{
IO;
int T=1;
cin>>T;
for(int ca=1;ca<=T;ca++)
{
ll res=0;
ll n,k;
cin>>n>>k;
if(k==1||k>=30)
{
printf("Case #%d: %d\n",ca,n);
continue;
}
ll m=pow(n,1.0/k);
for(int i=1;i<=m;i++)
{
ll l=pow(i,k);
ll r=min(n,(long long)pow(i+1,k)-1);
res+=r/i-(l-1)/i;
}
printf("Case #%d: %d\n",ca,res);
}
return 0;
}
K. Kingdom’s Power
大佬题解1大佬题解2
看了大佬的题解,我想了一个贪心:把所有叶子拿出来,然后按照深度排序,依次遍历每个叶子,当前叶子对答案的贡献:要么从前一个叶子过来的费用(lca求一下即可)要么从根节点过来的费用。然而TLE了,也不知道这样贪心对不对先记下来吧。顺便存个tarjan求lca的板子
错误orTLE代码
//TLE
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<random>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=1e9+7;
const int N=1000010;
int h[N],e[N],ne[N],idx;
void add(int a,int b){e[idx]=b,ne[idx]=h[a],h[a]=idx++;}
int dep[N];
int res,n;
int leaf[N],cnt;
bool cmp(int x,int y){return dep[x]<dep[y];}
void dfs1(int u)
{
int now=0;
for(int i=h[u];i!=-1;i=ne[i])
{
int t=e[i];
now++;
dep[t]=dep[u]+1;
dfs1(t);
}
if(!now) leaf[++cnt]=u;
}
// tarjan 求lca
vector<pii> q[N];
int anc[N],st[N],p[N];
int find(int x) {return x==p[x]?x:p[x]=find(p[x]);}
void tarjan(int u)
{
st[u]=1;//遍历但未回溯
for(int i=h[u];i!=-1;i=ne[i])
{
int j=e[i];
if(!st[j])
{
tarjan(j);//遍历子树
p[j]=u;//合并节点
}
}
for(auto &t:q[u])
{
int y=t.first,id=t.second;
if(st[y]==2)
anc[id]=find(y);
}
st[u]=2;//结束回溯
}
int main()
{
//IO;
int T=1;
scanf("%d",&T);
for(int ca=1;ca<=T;ca++)
{
cin>>n;
for(int i=1;i<=n;i++)
{
h[i]=-1;
dep[i]=0;
p[i]=i;
st[i]=0;
q[i].clear();
}
idx=cnt=res=0;
for(int i=2;i<=n;i++)
{
int p;
scanf("%d\n",&p);
add(p,i);
}
dfs1(1);
sort(leaf+1,leaf+1+cnt,cmp);
for(int i=2;i<=cnt;i++)
{
q[leaf[i]].push_back({leaf[i-1],i});
q[leaf[i-1]].push_back({leaf[i],i});
}
tarjan(1);
int res=dep[leaf[1]];
for(int i=2;i<=cnt;i++)
res+=min(dep[leaf[i]],dep[leaf[i]]+dep[leaf[i-1]]-2*dep[anc[i]]);
printf("Case #%d: %d\n",ca,res);
}
return 0;
}
AC代码
按照上述博客写的代码
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
//#pragma GCC optimize(2)
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<random>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=1e9+7;
const int N=1000010;
vector<int> e[N];
int dep[N],dist[N];
int res,n;
bool cmp(int x,int y) {return dist[x]<dist[y];};
void dfs1(int u)
{
for(auto &t:e[u])
{
dep[t]=dep[u]+1;
dfs1(t);
dist[u]=max(dist[u],dist[t]+1);
}
sort(e[u].begin(),e[u].end(),cmp);
}
int dfs2(int u,int cnt)
{
if(e[u].empty()) return res+=cnt,1;
for(auto &t:e[u]) cnt=min(dep[u],dfs2(t,cnt+1));
return cnt+1;
}
int main()
{
IO;
int T=1;
cin>>T;
for(int ca=1;ca<=T;ca++)
{
cin>>n;
for(int i=1;i<=n;i++)
{
e[i].clear();
dep[i]=dist[i]=0;
}
res=0;
for(int i=2;i<=n;i++)
{
int p;
cin>>p;
e[p].push_back(i);
}
dfs1(1);
dfs2(1,0);
printf("Case #%d: %d\n",ca,res);
}
return 0;
}