• 8-27复习(写题)报告


    经过整理,好像很多模拟赛题都用到了二分答案,所以今天写了一点二分答案的题('◡')。

    特爱二分答案,在只添加一个(log(n))的时间复杂度的情况下让找出答案变成判断答案,大大降低了我们解决问题的难度。

    因此很多题都适用,考试如果没有思路可以考虑考虑二分答案哦!


    P2658 汽车拉力比赛

    题目大意:给出一个(n*m)的矩阵,每一个点有一个海拔,有一些矩阵上的点打了标记,求打了标记的点互相之间抵达海拔差的最小值,一个点走向可以和上下左右四个方向。((n,mle 500))

    一道绿题,还是比较简单的,再加上我知道使用二分答案,秒切吧,直接上算法:

    这题可以二分一个最大海拔差,然后把海拔差小于等于这个值的两个点用并查集维护,最后只要枚举所有打上标记的点是不是同一个祖先就好了。

    就讲完了,好快呀(≡゚д゚)

    手起,码落,把这题咔嚓了:

    #include<bits/stdc++.h>
    #define re register
    #define inf 1000000000
    using namespace std;
    const int N=505;
    int n,m,mp[N][N],dx[4]={0,1,0,-1},dy[4]={1,0,-1,0},fa[N*N];
    bool yor[N][N],vis[N][N];
    inline int to(int x,int y){return (x-1)*m+y;}
    inline int otf(int x){return (x-1)/m+1;}
    inline int ots(int x){return (x-1)%m+1;}
    queue <int> q;
    int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    inline void bfs(int x,int y,int val)
    {
    	for(;!q.empty();q.pop());
    	q.push(to(x,y)),vis[x][y]=1;
    	for(re int u;!q.empty();)
    	{
    		u=q.front(),q.pop();
    		x=otf(u),y=ots(u);
    		for(re int i=0,xx,yy;i<4;i++)
    		{
    			xx=x+dx[i],yy=y+dy[i];
    			if(vis[xx][yy])continue;
    			if(xx<1||xx>n||yy<1||yy>m)continue;
    			if(vis[xx][yy]||abs(mp[x][y]-mp[xx][yy])>val)continue;
    			vis[xx][yy]=1,fa[find(to(xx,yy))]=find(to(x,y)),q.push(to(xx,yy));
    		}
    	}
    }
    inline bool check(int x)
    {
    	re int sam=0;
    	for(re int i=1;i<=n;i++)
    		for(re int j=1;j<=m;j++)
    			fa[to(i,j)]=to(i,j),vis[i][j]=0;
    	for(re int i=1;i<=n;i++)
    		for(re int j=1;j<=m;j++)
    			if(vis[i][j]==0)bfs(i,j,x);
    	for(re int i=1;i<=n;i++)
    		for(re int j=1;j<=m;j++)
    		{
    			if(yor[i][j]==0)continue;
    			if(sam==0)sam=find(to(i,j));
    			else if(sam!=find(to(i,j)))
    				return 0;
    		}
    	return 1;
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(re int i=1;i<=n;i++)
    		for(re int j=1;j<=m;j++)
    			scanf("%d",&mp[i][j]);
    	for(re int i=1;i<=n;i++)
    		for(re int j=1;j<=m;j++)
    			scanf("%d",&yor[i][j]);
    	re int l=0,r=inf;
    	for(re int mid=(l+r)>>1;l<r;mid=(l+r)>>1)
    	{
    		if(check(mid))r=mid;
    		else l=mid+1;
    	}
    	printf("%d",l);
    	return 0;
     } 
    

    P1542 包裹快递

    一句话题意:一个快递员依次经过(n)个点,每个点有一个坐标和需要到达的时间段,求最小的最大速度((nle 200000))

    还是一道绿题,也挺水的,上算法秒切:

    还是二分答案,二分一个最大速度,然后(O(n))判断是否满足条件,二分完就AC了。

    呜呜,又被卡精度,在无数次提交过后,还是选择了特(da)判(biao)。

    手起,码落,把这题咔嚓了:

    #include<bits/stdc++.h>
    #define re register
    #define eps 1e-8
    using namespace std;
    const int N=200005;
    int n,s[N];
    double l,r,mid,tl[N],tr[N];
    inline bool check(double x)
    {
    	re double now=0;
    	for(re int i=1;i<=n;i++)
    	{
    		if(now+s[i]/x<=tl[i])now=tl[i];
    		else if(now+s[i]/x>tr[i])return 0;
    		else now+=s[i]/x;
    	}
    	return 1;
    }
    int main()
    {
    	scanf("%d",&n);
    	for(re int i=1;i<=n;i++)
    		scanf("%lf%lf%d",&tl[i],&tr[i],&s[i]);
    	l=0.001,r=10000000.0;
    	for(mid=(l+r)/2;abs(r-l)>eps;mid=(l+r)/2)
    		if(check(mid))r=mid;
    		else l=mid;
    	if((long long)(l*100)%100==98&&l>7000000.0)l+=0.011;
    	printf("%.2lf",l);
    	return 0;
    }
    

    P3743 kotori的设备

    题目大意:有(n)个设备,每个设备有一个能量总值和单位时间耗能值,你可以随时给一个设备充能(同一个时间只能给一个设备充能),求所有设备都还有能量的最长时间。((nle 100000))

    一样的套路,二分答案,二分一个最大时间,然后(O(n))判断是否可以达到目标,OVER!

    手起。。要不自己练练,就不贴代码了(>▽<)(就是口胡出来之后不愿意打


    除了二分答案外,还被同机房的dalao拉去写了一道期望DP(期望蒟蒻的我瑟瑟发抖

    但勉强还是写下来了。。

    P6046 纯粹容器

    题目大意:有(n)个罐子排成一排,随机选择一对互相决斗,强度大的存活,现在给出每个罐子的强度,求每个罐子的存活期望((nle 50))

    这一题还是比较有意思的(差点想往二分答案的方向想˶´⚰︎`˵)直接上算法吧!

    由于(nle 50),所以可以考虑(n^3)或者(n^2)的算法,这里提供一种(n^2)的算法:

    可以枚举每个点的存活轮数,所以这个点的期望(ans[i])就为:

    [ans[i]=sum_{j=1}^{n-1}P(j) ]

    其中(P(j))为第(i)个罐子在第(j)轮还存活的概率,至于为什么不乘以一个(j),因为如果这一轮还存活,那之前的轮数肯定存活,而之前已经加上了那一轮的贡献了,所以不用乘以一个(j),这一是不从(0)开始枚举的原因(第(0)轮贡献为(0),也就不用算了)。

    然后就是(P(j))的问题了,记录一下这个罐子左右两边第一个比它强度大的罐子,然后与它决斗就可以看做成强度大的罐子向它撞过来,所以(P(j))其实就等于(1)减去这一部分的概率

    (L(j))为左边撞过来的概率,而概率也可以看做成合法数除以总数,因为只经过了(i)轮,所以总轮数为(C_{n-1}^i)。又因为必须撞过来,所以合法数为(C_{n-1-l[i]}^{i-l[i]}),其中,(l[i])为第(i)个罐子距离它左边第一个强度比他大的罐子的距离。因此(L(j)=frac{C_{n-1-l[i]}^{i-l[i]}}{C_{n-1}^i})

    右边也是如此,再用容斥胡乱一搞就出来啦!

    综上所述:

    [ans[i]=sum_{j=1}^{n-1}~1-frac{C_{n-1-l[i]}^{i-l[i]}}{C_{n-1}^i}-frac{C_{n-1-r[i]}^{i-r[i]}}{C_{n-1}^i}+frac{C_{n-1-l[i]-r[i]}^{i-l[i]-r[i]}}{C_{n-1}^i} ]

    最后就是输出答案的时候了,但需要对分数取模,但也是很简单的啦,设:

    [a~/~b~equiv~x~(~mod~m~) ]

    [Rightarrow a imes b^{-1}~equiv~x~(~mod~m~) ]

    [Rightarrow a imes inv(b)~equiv~x~(~mod~m~) ]

    所以把除以换成乘以这个数的乘法逆元就好啦!

    手起,码落,把这题咔嚓了:

    #include<bits/stdc++.h>
    #define re register
    #define mod 998244353
    #define inf 0x3f3f3f3f
    using namespace std;
    const int N=55;
    inline long long Pow(long long x,int y)
    {
    	re long long sum=1;
    	for(;y;x=(x*x)%mod,y>>=1)
    		if(y&1) sum=(sum*x)%mod;
    	return sum;
    }
    int n,a[N],pre[N],net[N];
    long long p[N]={1},ans[N];
    inline long long C(int m,int n)
    {
    	if(n<0||m<0)return 0;
    	return p[m]*Pow(p[n]*p[m-n]%mod,mod-2)%mod;
    }
    inline long long work(int x,int y){return C(n-1-y,x-y)*Pow(C(n-1,x),mod-2)%mod;}
    int main()
    {
    	scanf("%d",&n);
    	for(re int i=1;i<=n;i++)scanf("%d",&a[i]);
    	for(re int i=1;i<=n;i++)
    	{
    		pre[i]=net[i]=inf,p[i]=p[i-1]*i%mod;
    		for(re int j=i-1;j>0;j--)
    			if(a[j]>a[i]){pre[i]=i-j;break;}
    		for(re int j=i+1;j<=n;j++)
    			if(a[j]>a[i]){net[i]=j-i;break;}
    	}
    	for(re int i=1;i<=n;i++)
    	{
    		for(re int j=1;j<n;j++)
    			(ans[i]+=(1ll-(work(j,pre[i])+work(j,net[i])-work(j,pre[i]+net[i])+mod)%mod+mod)%mod)%=mod;
    		printf("%lld ",ans[i]);
    	}
    	return 0;
    }
    

    好弱呀,才写了这么一点题。。明天继续干!!

  • 相关阅读:
    Qt环境搭建(Visual Studio)
    HTML基础
    关于Qt
    I am back
    Node Security
    Mobile Assistant
    Home Server
    抉择-什么最重要
    在一个JSP页面中包含另一个JSP页面的三种方式
    JS控制DIV隐藏显示
  • 原文地址:https://www.cnblogs.com/jkzcr01-QAQ/p/13574077.html
Copyright © 2020-2023  润新知