zoukankan      html  css  js  c++  java
  • 2021.05.29【NOIP提高B组】模拟 总结

    T1

    题意:给你一个图,可以不花代价经过 (K) 条边,问从起点到终点的最短路

    考试的想法:设 (dis_{i,j}) 表示从起点免费了 (j) 条边到 (i) 的最短路

    然后直接跑 ( ext{spfa})

    结果:(WA)

    正解:分层图,需要考虑去到下一层就不能回来的情况

    分为 (K) 层,同一层的 (u,v) 边权不变,双向边,去下一层的单向边,权值为 0

    然后 ( ext{spfa}) 超时,用 ( ext{dijkstra}) 即可

    答案:免费任意次的最小值

    #include<bits/stdc++.h>
    using namespace std;
    const int N=10005,M=50005;
    int n,m,K,S,T,vis[N*12],ans=2100000000;
    int lst[N*12],nxt[M<<6],to[M<<6],qz[M<<6],dis[N*12],cnt;
    inline void Ae(int fr,int go,int vl) {
    	to[++cnt]=go,qz[cnt]=vl,nxt[cnt]=lst[fr],lst[fr]=cnt;
    }
    struct node {
    	int v,id;
    	node(int x,int y):v(x),id(y) {}
    	bool operator<(node x) const
    	{ return v>x.v; }
    };
    priority_queue<node> q;
    inline void dijkstra() {
    	memset(dis,100,sizeof(dis));
    	dis[S]=0;
    	q.push(node(0,S));
    	register int u;
    	while(!q.empty()) {
    		u=q.top().id,q.pop();
    		if(vis[u])continue; vis[u]=1;
    		for(int i=lst[u],v;i;i=nxt[i])
    			if(dis[v=to[i]]>dis[u]+qz[i]) {
    				dis[v]=dis[u]+qz[i];
    				q.push(node(dis[v],v));
    			}
    	}
    }
    int main() {
    	scanf("%d%d%d%d%d",&n,&m,&K,&S,&T);
    	++S,++T;
    	for(int i=1,u,v,w;i<=m;i++) {
    		scanf("%d%d%d",&u,&v,&w);
    		++u,++v,Ae(u,v,w),Ae(v,u,w);
    		for(int j=1;j<=K;j++) {
    			Ae(u+j*n,v+j*n,w);
    			Ae(v+j*n,u+j*n,w);
    			Ae(u+j*n-n,v+j*n,0);
    			Ae(v+j*n-n,u+j*n,0);
    		}
    	}
    	dijkstra();
    	for(int i=0;i<=K;i++)
    		ans=min(ans,dis[T+n*i]);
    	printf("%d",ans);
    }
    

    T2

    题目大意:给你许多条平行于 (x) 轴或 (y) 轴的线段

    问你最大的十字架大小,大小为 (R) 定义为从一个点按上下左右伸出 (R) 都有线段覆盖

    没有十字架输出 Human intelligence is really terrible

    考试时:把所有线段合起来再暴力匹配

    结果:看错题了:不会有两条共线线段有交点

    正解:可以二分大小 (R) ,若把所有线段左右(或上下)都减去 (R) 还有线段相交则 (R) 成立

    所以判断是否有线段相交,用扫描线

    T3

    题意:找出图中平均值最小的环,无环输出 PaPaFish is laying egg!

    考试的想法:二分答案,然后用 ( ext{spfa}) 一波复杂的操作

    正解:把所有边权减去 (mid) 若有负环说明 (mid) 可以

    #include<bits/stdc++.h>
    using namespace std;
    typedef double db;
    const db eps=1e-3;
    const int N=1005,M=10005;
    int n,m,cnt,lst[N],nxt[M],to[M],vis[N];
    db l,r,mid,ans=-1,qz[M],d[N],flg;
    inline void Ae(int fr,int go,int vl) {
    	to[++cnt]=go,qz[cnt]=1.0*vl;
    	nxt[cnt]=lst[fr],lst[fr]=cnt;
    }
    void spfa(int u) {
    	vis[u]=1;
    	for(int i=lst[u],v;i;i=nxt[i])
    		if(d[u]+qz[i]-mid<d[v=to[i]]) {
    			d[v]=d[u]+qz[i]-mid;
    			if(vis[v])flg=1;
    			else spfa(v);
    			if(flg)return;
    		}
    	vis[u]=0;
    }
    inline bool chk() {
    	memset(d,0,sizeof(d));
    	memset(vis,0,sizeof(vis));
    	flg=0;
    	for(int i=1;i<=n;i++)
    		if(!d[i]) {
    			spfa(i);
    			if(flg)return 1;
    		}
    	return 0;
    }
    int main() {
    	scanf("%d%d",&n,&m);
    	for(int i=1,u,v,w;i<=m;i++) {
    		scanf("%d%d%d",&u,&v,&w);
    		Ae(u,v,w);
    	}
    	r=10000000;
    	while(l+0.000001<r) {
    		mid=(l+r)/2.0;
    		if(chk())ans=r=mid;
    		else l=mid;
    	}
    	if(ans==-1)puts("PaPaFish is laying egg!");
    	else printf("%.2lf",floor(ans*1000)/1000);
    }
    

    T4

    题目大意:给你一个排列,求字典序比他大的第一个与他逆序对数一样的排列

    考试:直接树状数组+( ext{next_permutation}),光荣 30

    正解:观察样例可以发现有一段是不变的,考虑找到最大的这个下标

    (Nx(i))(a_i,a_{i+1},a_{i+2},cdots,a_{n}) 的逆序对个数

    则这个点要满足

    1. 后面有个数比他大
    2. 这个数对后面的数的逆序对小于 (Nx(i))

    找到后开始构造,设总共有 (all) 个逆序对

    发现这个点的数是后面中他的后继,于是 (ans_{p}) 填好了

    然后现在我们已经有(前面一部分逆序对数)+((ans_p)对后面一部分的逆序对数)个逆序对,记为 (sum)

    填剩下的位置,发现若 (填 (i) 产生的逆序对数)+(原有的 (sum))+(剩下最大逆序对数)(ge all),则合法

    好像可以二分,于是加一个权值线段树查找第 (k) 大即可。每次查询要更新 (sum)

    #include<bits/stdc++.h>
    #define G getchar
    #define P putchar
    using namespace std;
    inline int rd() {
    	register int x=0,f=1;
    	char C=getchar();
    	for(;C<'0'||C>'9';C=G())f&=C^45;
    	for(;C>'/'&&C<':';C=G())x=(x<<1)+(x<<3)+(C^48);
    	return f?x:-x;
    }
    void put(int x) { if(x>9)put(x/10); P(x%10|48); }
    typedef long long LL;
    const int N=500005;
    int n,x[N],pos,mx,y[N],l,r,mid,out;
    LL t[N],all,nx[N],val[N<<2],sum;
    inline LL MX(LL x) { return x*(x-1)/2; }
    inline void add(int p,int v) { for(;p<=n;p+=p&-p)t[p]+=1LL*v; }
    inline LL ask(LL p) { register LL s=0; for(;p;p-=p&-p)s+=t[p]; return s; }
    #define ls rt<<1
    #define rs rt<<1|1
    void mdy(int p,int v,int l,int r,int rt) {
    	if(l==r) { val[rt]+=v; return; }
    	register int mid=l+r>>1;
    	if(p<=mid)mdy(p,v,l,mid,ls);
    	else mdy(p,v,mid+1,r,rs);
    	val[rt]=val[ls]+val[rs];
    } 
    int fnd(int k,int l,int r,int rt) {
    	if(l==r)return l;
    	register int mid=l+r>>1;
    	if(k<=val[ls])return fnd(k,l,mid,ls);
    	else return fnd(k-val[ls],mid+1,r,rs);
    }
    #undef ls
    #undef rs
    int main() {
    	n=rd();
    	for(int i=1;i<=n;i++)x[i]=rd();
    	for(int i=n;i;i--) {
    		add(x[i],1),nx[i]=ask(x[i]-1);
    		all+=nx[i];
    	}
    	mx=x[n],sum=nx[n];
    	for(int i=n-1;i;i--) {
    		mx=max(mx,x[i]),sum+=nx[i];
    		if(x[i]^mx && nx[i]<sum) {
    			pos=i; break;
    		}
    	}
    	sum=0;
    	for(int i=1;i<pos;i++)put(x[i]),P(32),sum+=nx[i];
    	out=INT_MAX;
    	for(int i=pos+1;i<=n;i++)
    		if(x[i]>x[pos])out=min(out,x[i]);
    	put(out),P(32);
    	for(int i=pos;i<=n;i++)
    		if(x[i]^out)mdy(x[i],1,1,n,1),sum+=(x[i]<out);
    	for(int i=pos+1;i<=n;i++) {
    		l=1,r=n-i+1;
    		while(l<r) {
    			mid=l+r>>1;
    			if(mid-1+sum+MX(n-i)>=all)
    				r=mid;
    			else l=mid+1;
    		}
    		out=fnd(l,1,n,1),put(out),P(32);
    		sum+=l-1,mdy(out,-1,1,n,1);
    	}
    }
    

    总结

    这些题我该怎么想:

    T1:遇到图论不能单纯设状态,最好连边

    T2:认真看题+二分的运用+扫描线的题型

    T3:遇到环上值的题多想想负环,同时了解图的边权是可以变的

    T4:贪心策略一直不强,逆序对的构造要了解,同时多观察样例

    总结:最近的题知识点普遍不少,需要好好消化

  • 相关阅读:
    Python的if判断与while循环
    python基础之数据类型与变量
    网络基础之网络协议篇
    操作系统简介
    计算机基础之计算机硬件系统
    从头开始编写一个Orchard网上商店模块(3)
    从头开始编写一个Orchard网上商店模块(2)
    从头开始编写一个Orchard网上商店模块(1)
    var和dynamic的区别及如何正确使用dynamic ?
    [DOM Event Learning] Section 3 jQuery事件处理基础 on(), off()和one()方法使用
  • 原文地址:https://www.cnblogs.com/KonjakLAF/p/14833068.html
Copyright © 2011-2022 走看看