noi.ac上的做题记录
记录了从20.2.14至20.2.23在noi.ac的做题记录,总计11题。
1、#1508.三位偏序
寒假学过的CDQ算法的模板题,温习了一遍。
CDQ算法流程可以理解为:
先以第一维为第一关键字排序。
由于对于第\(i\)个元素,只有它之前的元素才能对它产生贡献,所以维护以第二维为关键字的树状数组,从前到后找第二维比他小的元素。
如何保证第二维有序呢?可以采用基于分治思想的归并排序,关键字为第二维。
考虑一个子问题,需要排序的序列的左右两个以中心元素为分界线的子序列已经有序。由于左子序列的第一维全部比右子序列小,所以只有左子序列可以对它产生贡献。
所以直接归并排序,左右各维护一个指针扫即可。最后答案即为贡献之和。
\(code\):
/********************************
This code is made by ghy.
Oj: noi.ac
Language: C++
Status: AC
Complexity: O(nlognlogk)
********************************/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
#include <utility>
#include <cctype>
#include <stack>
#define il inline
#define ll long long
#define rg register
#define mp(a,b) make_pair(a,b);
#define pb(a) push_back(a);
#define mst(a,b) memset(a,b,sizeof a)
using namespace std;
il int read(){
rg int x=0,f=1; rg char c=getchar();
while(c<'0' || c>'9'){
if(c=='-') f=-1; c=getchar();
}
while(c>='0' && c<='9'){
x=(x<<1)+(x<<3)+(c^48); c=getchar();
}
return x*f;
}
const int Inf1=0x3f3f3f3f;
const int Inf2=1e9;
const int mod=1e9+7;
const int N=2e5+5;
int n,ccnt,k,numm;
int ans[N],bit[N];
struct Flower{
int a,b,c,num,cnt;
}f[N],cdq[N];
il bool cmp1(Flower f1,Flower f2){
return f1.a==f2.a?f1.b==f2.b?f1.c<f2.c:f1.b<f2.b:f1.a<f2.a;
}
il bool cmp2(Flower f1,Flower f2){
return f1.b==f2.b?f1.c<f2.c:f1.b<f2.b;
}
il int lowbit(int x){
return x&(-x);
}
il void add(int x,int val){
while(x<=k){
bit[x]+=val;
x+=lowbit(x);
}
}
il int sum(int x){
int ret=0;
while(x){
ret+=bit[x];
x-=lowbit(x);
}
return ret;
}
il void CDQ(int l,int r){
if(l==r)
return;
int mid=(l+r)>>1;
CDQ(l,mid);
CDQ(mid+1,r);
sort(cdq+l,cdq+mid+1,cmp2);
sort(cdq+mid+1,cdq+r+1,cmp2);
int pnt1=l,pnt2;
for(pnt2=mid+1;pnt2<=r;++pnt2){
while(cdq[pnt1].b<=cdq[pnt2].b && pnt1<=mid){
add(cdq[pnt1].c,cdq[pnt1].num);
++pnt1;
}
cdq[pnt2].cnt+=sum(cdq[pnt2].c);
}
for(rg int i=l;i<pnt1;++i)
add(cdq[i].c,-cdq[i].num);
}
int main(){
n=read();
k=read();
for(rg int i=1;i<=n;++i){
f[i].a=read();
f[i].b=read();
f[i].c=read();
}
sort(f+1,f+n+1,cmp1);
for(rg int i=1;i<=n;++i){
++numm;
if(f[i].a!=f[i+1].a || f[i].b!=f[i+1].b || f[i].c!=f[i+1].c){
++ccnt;
cdq[ccnt].a=f[i].a;
cdq[ccnt].b=f[i].b;
cdq[ccnt].c=f[i].c;
cdq[ccnt].num=numm;
numm=0;
}
}
CDQ(1,ccnt);
for(rg int i=1;i<=ccnt;++i)
ans[cdq[i].cnt+cdq[i].num-1]+=cdq[i].num;
for(rg int i=0;i<n;++i)
printf("%d\n",ans[i]);
return 0;
}
2、#1465.青蛙的约会
exgcd的题目,复习了一下。设跳k次后相遇,则\((x+mk)\)%\(L\)=\((y+nk)\)%\(L\)。直接用exgcd套即可。
值得注意的一点是,我起初把exgcd函数定为了int型,但先返回了数据,函数结束了才进行了修改。起初没意识到这一点,只有50分,后来才改对。
\(code:\)
/********************************
This code is made by ghy.
Oj: noi.ac
Language: C++
Status: AC
Complexity: O(log^2n)
********************************/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
#include <utility>
#include <map>
#include <cstdlib>
#include <ctime>
#define il inline
#define ll long long
#define rg register
#define mp(a,b) make_pair(a,b);
#define pb(a) push_back(a);
#define mst(a,b) memset(a,b,sizeof a)
using namespace std;
il ll read(){
rg ll x=0,f=1; rg char c=getchar();
while(c<'0' || c>'9'){
if(c=='-') f=-1; c=getchar();
}
while(c>='0' && c<='9'){
x=(x<<1)+(x<<3)+(c^48); c=getchar();
}
return x*f;
}
const int Inf1=0x3f3f3f3f;
const int Inf2=1e9;
const int mod=1e9+7;
il ll exgcd(ll a,ll b,ll &x,ll &y){
if(!b){
x=1;
y=0;
return a;
}
ll ans=exgcd(b,a%b,x,y);
ll tmp=x;
x=y;
y=tmp-a/b*y;
return ans;
}
int main(){
ll x=read();
ll y=read();
ll a=x-y;
ll m=read();
ll n=read();
ll b=n-m;
ll l=read();
if(b<0){
b=-b;
a=-a;
}
ll x1=0,y1=0;
ll ans=exgcd(b,l,x1,y1);
ll mod=l/ans;
if(a%ans!=0)
puts("Impossible");
else
printf("%lld\n",(x1*(a/ans)%mod+mod)%mod);
return 0;
}
3、#1415.宠物收养所
复习了一遍set的用法。
观察到,任意时间,在店内的只有可能全是人或全是宠物。既可以人找宠物,也可以宠物找人。
所以我们可以记一下当前是什么。如果与当前店中的一样,就直接加入。反之,就找前驱或后继知道匹配为止。
\(code:\)
/******************************
This code is made by ghy.
Oj: noi.ac
Language: C++
Status: AC
Complexity: O(nlogn)
*****************************/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <map>
#include <set>
#include <bitset>
#include <utility>
#include <ctime>
#define ll long long
#define rg register
#define il inline
#define pb(a) push_back(a)
#define File(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
#define mst(a,b) memset(a,b,sizeof a)
#define mp(a,b) make_pair(a,b)
#define smallrootpile priority_queue <int,vector<int>,greater<int> >
#define bigrootpile priority_queue <int>
using namespace std;
il int read(){
rg int x=0,f=1; rg char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') f=-1; c=getchar();
}
while(c>='0'&&c<='9'){
x=(x<<1)+(x<<3)+(c^48); c=getchar();
}
return x*f;
}
const int Inf1=0x3f3f3f3f;
const int Inf2=1e9,mod=1e6;
set <int> s;
set <int> :: iterator l,r;
int n,x,y,opt;
ll ans;
il void find(int x){
l=--s.lower_bound(x);
r=s.lower_bound(x);
if((x-*l)<=(*r-x) && (*l!=-Inf2)){
ans=(ans+x-*l)%mod;
s.erase(l);
}
else{
ans=(ans+*r-x)%mod;
s.erase(r);
}
}
int main(){
s.insert(-Inf2);
s.insert(Inf2);
n=read();
while(n--){
x=read();
y=read();
if(s.size()==2){
opt=x;
s.insert(y);
}
else if(x==opt)
s.insert(y);
else
find(y);
}
printf("%lld\n",ans);
return 0;
}
4、#42.\(queen\)
先将皇后以行为第一关键字,列为第二关键字排序。
考虑新加入一个皇后。
如果行上已有皇后,且无皇后继续加入,即排序后下一个皇后为下一行,则做贡献的只有左侧的一个皇后。
如果行上已有皇后,且有皇后继续加入,即排序后下一个皇后为本行,则左右两侧的侧的皇后都做贡献。
如果行上暂无皇后,标记行为已有皇后,若无皇后加入,则贡献为\(0\)。反之则为1。
列亦然,对角线亦然。只要判断左右对角线。注意对角线相同的坐标和也相同。
\(code\):
/********************************
This code is made by ghy.
Oj: noi.ac
Language: C++
Status: AC
Complexity: O(mlogm)
********************************/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
#include <utility>
#include <map>
#include <cstdlib>
#include <ctime>
#define il inline
#define ll long long
#define rg register
#define mp(a,b) make_pair(a,b);
#define pb(a) push_back(a);
#define mst(a,b) memset(a,b,sizeof a)
using namespace std;
il int read(){
rg int x=0,f=1; rg char c=getchar();
while(c<'0' || c>'9'){
if(c=='-') f=-1; c=getchar();
}
while(c>='0' && c<='9'){
x=(x<<1)+(x<<3)+(c^48); c=getchar();
}
return x*f;
}
const int Inf1=0x3f3f3f3f;
const int Inf2=1e9;
const int mod=1e9+7;
const int N=1e5+5;
int n,m,cnt[N],ans[10];
int rw[N],ln[N],dgn1[N<<1],dgn2[N<<1];
struct Queen{
int x,y;
il bool operator<(const Queen &q1)const{
return x==q1.x?y<q1.y:x<q1.x;
}
}q[N];
int main(){
n=read();
m=read();
for(rg int i=1;i<=m;++i)
q[i]=(Queen){read(),read()};
sort(q+1,q+m+1);
for(rg int i=1;i<=m;++i){
int x=q[i].x,y=q[i].y;
if(rw[x]){
++cnt[i];
++cnt[rw[x]];
}
if(ln[y]){
++cnt[i];
++cnt[ln[y]];
}
if(dgn1[x+y]){
++cnt[i];
++cnt[dgn1[x+y]];
}
if(dgn2[n+x-y]){
++cnt[i];
++cnt[dgn2[n+x-y]];
}
rw[x]=ln[y]=dgn1[x+y]=dgn2[n+x-y]=i;
}
for(rg int i=1;i<=m;++i)
++ans[cnt[i]];
for(rg int i=0;i<=8;++i)
printf("%d ",ans[i]);
return 0;
}
5、#36.列队
把\(n×m\)个数按从大到小顺序填入,填入时,本行已填入的数的个数就是比它大的数的个数。列亦然。所以询问可以做到\(O(1)\)。
\(code\):
/********************************
This code is made by ghy.
Oj: noi.ac
Language: C++
Status: AC
Complexity: O(nmlogn)
********************************/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
#include <utility>
#include <map>
#include <cstdlib>
#include <ctime>
#define il inline
#define ll long long
#define rg register
#define mp(a,b) make_pair(a,b);
#define pb(a) push_back(a);
#define mst(a,b) memset(a,b,sizeof a)
using namespace std;
il int read(){
rg int x=0,f=1; rg char c=getchar();
while(c<'0' || c>'9'){
if(c=='-') f=-1; c=getchar();
}
while(c>='0' && c<='9'){
x=(x<<1)+(x<<3)+(c^48); c=getchar();
}
return x*f;
}
const int Inf1=0x3f3f3f3f;
const int Inf2=1e9;
const int mod=1e9+7;
const int N=1005;
int n,m,q,ans[N][N];
struct Classmate{
int x,y,val,id;
il bool operator<(const Classmate &c)const{
return val>c.val;
}
}a[N*N],ord[N];
int main(){
n=read();
m=read();
q=read();
for(rg int i=1;i<=n*m;++i){
a[i].id=i;
a[i].val=read();
}
for(rg int i=1;i<=n;++i){
for(rg int j=1;j<=m;++j)
ord[j]=a[(i-1)*m+j];
sort(ord+1,ord+m+1);
for(rg int j=1;j<=m;++j)
a[ord[j].id].x=j;
}
for(rg int i=1;i<=m;++i){
for(rg int j=1;j<=n;++j)
ord[j]=a[(j-1)*m+i];
sort(ord+1,ord+n+1);
for(rg int j=1;j<=n;++j)
a[ord[j].id].y=j;
}
for(rg int i=1;i<=n;++i)
for(rg int j=1;j<=m;++j)
++ans[a[(i-1)*m+j].x][a[(i-1)*m+j].y];
while(q--)
printf("%d\n",ans[read()][read()]);
return 0;
}
6、#30.\(candy\)
依题意可知,价格一定,为使收益最大,必然要从大往小选,可以记录一下后缀和。
枚举\(A\)店的价值更小还是\(B\)店的价值更小。枚举那家店由最大贡献的商品取到第几个,再二分另一家店在保证最大贡献,且大于那家店的贡献的情况下,由最大贡献的商品取到第几个。最后\(ans\)即为最大值。
\(code\):
/********************************
This code is made by ghy.
Oj: noi.ac
Language: C++
Status: AC
Complexity: O(nlogn)
********************************/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
#include <utility>
#include <map>
#include <cstdlib>
#include <ctime>
#define il inline
#define ll long long
#define rg register
#define mp(a,b) make_pair(a,b);
#define pb(a) push_back(a);
#define mst(a,b) memset(a,b,sizeof a)
using namespace std;
il int read(){
rg int x=0,f=1; rg char c=getchar();
while(c<'0' || c>'9'){
if(c=='-') f=-1; c=getchar();
}
while(c>='0' && c<='9'){
x=(x<<1)+(x<<3)+(c^48); c=getchar();
}
return x*f;
}
const int Inf1=0x3f3f3f3f;
const int Inf2=1e9;
const int mod=1e9+7;
const int N=1e5+5;
int n,w,l,mid,r;
int a[N],b[N];
ll suma[N],sumb[N],ans;
int main(){
n=read();
w=read();
for(rg int i=1;i<=n;++i)
a[i]=read();
for(rg int i=1;i<=n;++i)
b[i]=read();
for(rg int i=1;i<=n;++i){
suma[i]=suma[i-1]+a[n-i+1];
sumb[i]=sumb[i-1]+b[n-i+1];
}
for(rg int i=1;i<=n;++i){
l=1;
r=n;
while(l<r){
mid=(l+r)>>1;
if(suma[i]<=sumb[mid])
r=mid;
else
l=mid+1;
}
ans=max(ans,min(suma[i],sumb[l])-w*(i+l));
}
for(rg int i=1;i<=n;++i){
l=1;
r=n;
while(l<r){
mid=(l+r)>>1;
if(sumb[i]<=suma[mid])
r=mid;
else
l=mid+1;
}
ans=max(ans,min(suma[l],sumb[i])-w*(i+l));
}
printf("%lld\n",ans);
return 0;
}
7、#48.\(fac\)
看到n有\(10^{10000}\),就知道有问题。看到要模\(k\),想了一下,发现\(n>=k\)时,结果直接为\(0\),\(n<k\)的情况,直接爆算即可。
唯一要注意的就是读入。读入\(n\)时,发现大于\(8\)位后,可以一直\(getchar()\),但后面的空格也会被读入,所以读入\(k\)时,直接算第一位即可。
\(code\):
/********************************
This code is made by ghy.
Oj: noi.cn
Language: C++
Status: AC
Complexity: O(n)
********************************/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
#include <utility>
#include <map>
#include <cstdlib>
#include <ctime>
#define il inline
#define ll long long
#define rg register
#define mp(a,b) make_pair(a,b);
#define pb(a) push_back(a);
#define mst(a,b) memset(a,b,sizeof a)
using namespace std;
bool flg;
il int read(){
rg int x=0,f=1; rg char c=getchar();
if(flg)
while(c>='0' && c<='9')
c=getchar();
while(c<'0' || c>'9'){
if(c=='-') f=-1; c=getchar();
}
while(c>='0' && c<='9'){
x=(x<<1)+(x<<3)+(c^48); c=getchar();
}
return x*f;
}
il int readd(){
rg int x=0,f=1; rg char c=getchar();
while(c<'0' || c>'9'){
if(c=='-') f=-1; c=getchar();
}
while(c>='0' && c<='9'){
x=(x<<1)+(x<<3)+(c^48);
if(x>=1e8){
flg=1;
return 1e8;
}
c=getchar();
}
return x*f;
}
const int Inf1=0x3f3f3f3f;
const int Inf2=1e9;
const int mod=1e9+7;
int a,b,ans=1;
int main(){
a=readd();
b=read();
if(a>=b){
puts("0");
return 0;
}
while(a>0){
ans=(1ll*ans*a)%b;
--a;
}
printf("%d\n",ans%b);
return 0;
}
8、#37.染色
一道dp题。
令\(dp[i][j]\)为前\(i\)个格子中填色,其中从后往前最长一段不包含相同颜色格子的后缀长度为\(j\)的方案数。
考虑当前位置,如果不选择最后\(j\)个格子中的颜色,那么最长后缀长度就变成\(j+1\),有\(m-j\)种颜色可供选择。
若选择,那么最长后缀长度就会变成\(1,2,...,j\),各有\(1\)种颜色转移。
所以可以得出方程:\(dp[i][j]=(m-j+1)dp[i-1][j-1]+sigma(k>=j)dp[i-1][k]\)
\(code\):
/********************************
This code is made by ghy.
Oj: noi.cn
Language: C++
Status: AC
Complexity: O(nm)
********************************/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
#include <utility>
#include <map>
#include <cstdlib>
#include <ctime>
#define il inline
#define ll long long
#define rg register
#define mp(a,b) make_pair(a,b);
#define pb(a) push_back(a);
#define mst(a,b) memset(a,b,sizeof a)
using namespace std;
il int read(){
rg int x=0,f=1; rg char c=getchar();
while(c<'0' || c>'9'){
if(c=='-') f=-1; c=getchar();
}
while(c>='0' && c<='9'){
x=(x<<1)+(x<<3)+(c^48); c=getchar();
}
return x*f;
}
const int Inf1=0x3f3f3f3f;
const int Inf2=1e9;
const int mod=1e9+7;
const int N=5005;
int n,m,p;
ll ans,dp[N][N],sum[N][N];
int main(){
n=read();
m=read();
p=read();
dp[0][0]=1;
for(rg int i=1;i<=n;++i){
for(rg int j=1;j<=min(i,m-1);++j)
dp[i][j]=(((dp[i][j]+sum[i-1][j])%p)+((((m-j+1)%p)*dp[i-1][j-1])%p))%p;
for(rg int j=m-1;j>0;--j)
sum[i][j]=(sum[i][j+1]+dp[i][j])%p;
}
for(rg int i=1;i<m;++i)
ans=(ans+dp[n][i])%p;
printf("%d\n",ans);
return 0;
}
9、#60.\(ball\)
观察到,操作\(2\)限定了球是有序的,操作\(1\)又要插入,所以开一个\(set\)维护每个球的位置。
操作\(1\)直接加入,操作\(2\)可以抽象为每个球都向左移一个,去掉最左的球,在墙前加一个球,具体证明自己画图理解一下即可。
在\(set\)中一个一个减固然是爆炸的。所以我们记一个\(cnt\)表示当前减了多少个\(1\)。
这样还要注意一点,新插入的球也默认减了\(cnt\),所以得插入比读入数多\(cnt\)的坐标。
\(code\):
/********************************
This code is made by ghy.
Oj: noi.ac
Language: C++
Status: AC
Complexity: O(nlogn)
********************************/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
#include <utility>
#include <map>
#include <cstdlib>
#include <ctime>
#define il inline
#define ll long long
#define rg register
#define mp(a,b) make_pair(a,b);
#define pb(a) push_back(a);
#define mst(a,b) memset(a,b,sizeof a)
using namespace std;
il int read(){
rg int x=0,f=1; rg char c=getchar();
while(c<'0' || c>'9'){
if(c=='-') f=-1; c=getchar();
}
while(c>='0' && c<='9'){
x=(x<<1)+(x<<3)+(c^48); c=getchar();
}
return x*f;
}
const int Inf1=0x3f3f3f3f;
const int Inf2=1e9;
const int mod=1e9+7;
int n,q,p,cnt;
set <int> s;
int main(){
n=read();
q=read();
p=read();
for(rg int i=1;i<=n;++i)
s.insert(read());
while(q--){
if(read()==1)
s.insert(read()+cnt);
else{
s.erase(s.begin());
s.insert(p+(cnt++));
}
}
while(s.size()){
printf("%d ",*s.begin()-cnt);
s.erase(s.begin());
}
return 0;
}
10、#64.\(sort\)
假设我们已经知道第\(L\)的数是\(x\),第\(R\)的数是\(y\)。
那其实就只需要找到[x+1,y+1]这一段,然后再加上一定数量的x和y就是答案。
于是可以枚举\(a[i]\),二分\(b[j]\)找到。
然后考虑怎么找第\(L\)的数是多少。
其实是二分出一个数,然后比较\(L\)和小于它的个数。
这个小于它的个数怎么算呢,还是二分,细节见代码。
惨痛教训:不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!(本题将\(L\)与\(l\)弄混了)
\(code\):
/********************************
This code is made by ghy.
Oj: noi.ac
Language: C++
Status: AC
Complexity: O(nlog^2n)
********************************/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
#include <utility>
#include <map>
#include <cstdlib>
#include <ctime>
#define il inline
#define rg register
#define int long long
#define mp(a,b) make_pair(a,b);
#define pb(a) push_back(a);
#define mst(a,b) memset(a,b,sizeof a)
using namespace std;
il int read(){
rg int x=0,f=1; rg char c=getchar();
while(c<'0' || c>'9'){
if(c=='-') f=-1; c=getchar();
}
while(c>='0' && c<='9'){
x=(x<<1)+(x<<3)+(c^48); c=getchar();
}
return x*f;
}
const int N=1e5+5;
int n,l,r;
int a[N],b[N],ans[N];
il int rk(int val){
int cnt=0;
for(rg int i=1;i<=n;++i){
int L=0,R=n,num=0;
while(L<=R){
int mid=(L+R)>>1;
if(a[i]+b[mid]<val){
L=mid+1;
num=mid;
}
else
R=mid-1;
}
cnt+=num;
}
return cnt;
}
signed main(){
n=read();
l=read();
r=read();
for(rg int i=1;i<=n;++i)
a[i]=read();
for(rg int i=1;i<=n;++i)
b[i]=read();
sort(a+1,a+n+1);
sort(b+1,b+n+1);
int L=a[1]+b[1];
int R=a[n]+b[n];
int ansl,ansr;
while(L<=R){
int mid=(L+R)>>1;
if(rk(mid)>=l)
R=mid-1;
else{
L=mid+1;
ansl=mid;
}
}
L=a[1]+b[1];
R=a[n]+b[n];
while(L<=R){
int mid=(L+R)>>1;
if(rk(mid)>=r)
R=mid-1;
else{
L=mid+1;
ansr=mid;
}
}
int mn,mx,cnt=0;
for(rg int i=1;i<=n;++i){
L=1;
R=n;
mn=n+1;
mx=-1;
while(L<=R){
int mid=(L+R)>>1;
if(a[i]+b[mid]>ansl){
mn=mid;
R=mid-1;
}
else
L=mid+1;
}
L=1;
R=n;
while(L<=R){
int mid=(L+R)>>1;
if(a[i]+b[mid]<ansr){
mx=mid;
L=mid+1;
}
else
R=mid-1;
}
for(rg int j=mn;j<=mx;++j)
ans[++cnt]=a[i]+b[j];
}
for(rg int i=l;i<=min(r,rk(ansl+1));++i)
printf("%lld ",ansl);
sort(ans+1,ans+cnt+1);
for(rg int i=1;i<=cnt;++i)
printf("%lld ",ans[i]);
for(rg int i=cnt+min(r,rk(ansl+1))+1;i<=r;++i)
printf("%lld ",ansr);
return 0;
}
11、#54.\(inform\)
最小生成树板子题。
首先注意一点:第一次空降在哪个点都行,因为最小生成树只有一棵,空降任意点费用也想同。
最小生成树的过程中,如果没有点到树的距离比空降的费用小,就直接空降与树相邻的点即可。
惨痛教训:读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!(本题忘了读“平方”)
\(code\):
/********************************
This code is made by ghy.
Oj: noi.ac
Language: C++
Status: AC
Complexity: O(n^2)
********************************/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
#include <utility>
#include <map>
#include <cstdlib>
#include <ctime>
#define il inline
#define ll long long
#define rg register
#define mp(a,b) make_pair(a,b);
#define pb(a) push_back(a);
#define mst(a,b) memset(a,b,sizeof a)
using namespace std;
il int read(){
rg int x=0,f=1; rg char c=getchar();
while(c<'0' || c>'9'){
if(c=='-') f=-1; c=getchar();
}
while(c>='0' && c<='9'){
x=(x<<1)+(x<<3)+(c^48); c=getchar();
}
return x*f;
}
const int Inf1=0x3f3f3f3f;
const int Inf2=1e9;
const int mod=1e9+7;
const int N=5005;
int n,v,mn,id;
int x[N],y[N];
ll dis[N][N],d[N],ans;
bool inque[N];
int main(){
n=read();
v=read();
for(rg int i=1;i<=n;++i){
x[i]=read();
y[i]=read();
}
for(rg int i=1;i<=n;++i)
for(rg int j=i+1;j<=n;++j)
dis[i][j]=dis[j][i]=1ll*(x[i]-x[j])*(x[i]-x[j])+1ll*(y[i]-y[j])*(y[i]-y[j]);
inque[1]=1;
for(rg int i=2;i<=n;++i)
d[i]=dis[1][i];
for(rg int i=1;i<n;++i){
mn=0x7fffffff;
for(rg int j=1;j<=n;++j)
if(!inque[j] && d[j]<mn){
id=j;
mn=d[j];
}
inque[id]=1;
ans+=min(d[id],1ll*v);
for(rg int j=1;j<=n;++j)
if(!inque[j])
d[j]=min(d[j],dis[id][j]);
}
printf("%lld\n",ans+v);
return 0;
}

浙公网安备 33010602011771号