• 2019-10-22


    T1

    一道很水的题 其实对于本蒟蒻来说也没有那么水 只需要知道最小值总是会在零点的时候取到 因此将零点排序之后枚举当(x=)每个零点时 整个式子的值 然后用ans来存最小值。
    需要注意的地方:1.因为我用的方法是用前缀和,后缀和优化,所以一定要将零点排序
    2.当(a=0)的时候 零点算不出来。。我是将零点赋为极大值
    3.当(a<0)的时候 将(a,b)都取反
    因为在零点左边的所有式子一定大于零 在零点右边的式子一定小于零 所以可以用前缀和后缀和来实现

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #define ll long long 
    using namespace std;
    const ll maxn=300010;
    const ll inf=0x3f3f3f3f;
    ll read()
    {
    	ll x=0,f=1;
    	char ch=getchar();
    	while(ch<'0' || ch>'9')
    	{
    		if(ch=='-')	f=-1;
    		ch=getchar();
    	}
    	while(ch>='0' && ch<='9')
    	{
    		x=x*10+ch-'0';
    		ch=getchar();
    	}
    	return x*f;
    }
    
    ll n,prea[maxn],preb[maxn],sufa[maxn],sufb[maxn];
    ll a[maxn],b[maxn];
    struct node{
    	ll prea,preb,sufa,sufb,id,a,b;
    	long double zero;
    	#define prea(x) job[x].prea
    	#define preb(x) job[x].preb
    	#define sufa(x) job[x].sufa
    	#define sufb(x) job[x].sufb
    	#define id(x) job[x].id
    	#define a(x) job[x].a
    	#define b(x) job[x].b
    }job[maxn];
    long double ans=999999999999999,now,bj;
    
    inline bool cmp(node x,node y)
    {
    	return x.zero<y.zero || (x.zero==y.zero && x.id<y.id);
    }
    
    int main()
    {
    	freopen("spongebob.in","r",stdin);
    	freopen("spongebob.out","w",stdout);
    	n=read();
    	for(ll i=1;i<=n;i++)
    	{
    		a(i)=read(),b(i)=read();
    		if(a(i)<0){
    			a(i)=-a(i);b(i)=-b(i);
    		}
    		else if(a(i)==0){
    			job[i].zero=0x3f3f3f3f*1.0;
    		}
    		job[i].zero=-1.0*(double)b(i)/(double)a(i);	
    	}
    	sort(job+1,job+1+n,cmp);
    	for(int i=1;i<=n;i++)
    	{
    		prea(i)=prea(i-1)+a(i);
    		preb(i)=preb(i-1)+b(i);
    	}
    	for(ll i=n;i>=1;i--)
    	{
    		sufa(i)=sufa(i+1)+a(i);
    		sufb(i)=sufb(i+1)+b(i);
    	}
    	for(ll i=1;i<=n;i++)
    	{
    		now=0;
    		now=job[i].zero*prea(i)*1.0+preb(i)*1.0-job[i].zero*sufa(i)*1.0-sufb(i)*1.0;
    		if(ans>now)	ans=now,bj=job[i].zero;
    	}
    	printf("%.5f",(double)ans);
    	return 0;
    }
    

    T2

    这道题暴力可以拿(30pts)呢! 所以说为什么我的分块才(20pts)蒟蒻表示一脸懵逼
    那么暴力的方法就不用说了吧 每次都扫描一遍。
    然后我们来看正解
    首先分析如果对于任意的(i∈[0,n-1]),(h[i] < h[i+ 1]) 均可以对([a[i]+1,a[i+1]])造成一点贡献 当水平线到了([a[i]+1,a[i+1]])时,因为(a[i])小于该区间,(a[i+1])等于该区间 所以当水平线在这个范围内 相当于会新增加一个岛屿 所以最终你需要输出的答案就是当前水平线对应的值是多少
    因为这个是待修的 所以可以用线段树和树状数组
    那么接下来就上代码啦!

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    const int maxn=600010;
    
    int read()
    {
    	int x=0,f=1;
    	char ch=getchar();
    	while(ch<'0' || ch>'9')
    	{
    		if(ch=='-')	f=-1;
    		ch=getchar();
    	}
    	while(ch>='0' && ch<='9')
    	{
    		x=x*10+ch-'0';
    		ch=getchar();
    	}
    	return x*f;
    }
    
    int h[maxn],n,m;
    int tree[maxn];
    int last=0;
    
    int lowbit(int x)
    {
    	return x&(-x);
    }
    
    void add(int x,int val)
    {
    	x++;
    	for(;x<=maxn;x+=lowbit(x)) 
    		tree[x]+=val;
    }
    int query(int x)
    {
    	int ans=0;
    	for(;x;x-=lowbit(x)) 
    		ans+=tree[x];
    	return ans;
    }
    int main()
    {
    	n=read();m=read();
    	for(int i=1;i<=n;i++)
    		h[i]=read();
    	for(int i=1;i<=n;i++)
    	{
    		if(h[i-1]<h[i])
    		{
    			add(h[i-1],1);
    			add(h[i],-1);
    		}
    	}
    	for(int i=1;i<=m;i++)
    	{
    		char type;
    		scanf("%s",&type);
    		if(type=='Q')
    		{
    			int q=read();
    			q=q^last;
    			printf("%d
    ",last=query(q));
    		}
    		
    		else
    		{
    			int x=read(),y=read();
    			x=x^last;y=y^last;
    			if(h[x-1]<h[x])
    			{
    				add(h[x-1],-1);add(h[x],1);
    			}	
    			if(h[x]<h[x+1])
    			{
    				add(h[x],-1);add(h[x+1],1);
    			}
    			h[x]=y;
    			if(h[x-1]<h[x])
    			{
    				add(h[x-1],1);
    				add(h[x],-1);
    			}
    			if(h[x]<h[x+1])
    			{
    				add(h[x],1);
    				add(h[x+1],-1);
    			}
    		}
    	}
    	return 0;
    }
    

    T3

    这道题 我觉得我不会很正常(会了才奇怪呢)
    暴力:每一条边都枚举其情况 复杂度(O(2^m),20pts)
    正解:首先易证:此题肯定有解!
    对于每一个点如果同一个权值的边出现了两次 那么就可以考虑将这两条边删了 加入一条新的边 关于这道题的细节真的很多 具体的话看代码 我tm原地转圈圈懵逼

    #include<bits/stdc++.h>
    using namespace std;
    #define in read()
    int in{
    	int cnt=0,f=1;char ch=0;
    	while(!isdigit(ch)){
    		ch=getchar();if(ch=='-')f=-1;
    	}
    	while(isdigit(ch)){
    		cnt=cnt*10+ch-48;
    		ch=getchar();
    	}return cnt*f;
    }
    
    struct node{
    	int id,to,d;
    }a[2][2000003];
     
    int n,m;
    int depend[2000003];
    int rev[2000003];
    //rev 数组 解决的问题是 在最后的时候 ans[i] 由其 depend的边转换过来时 是否需要取反 
    int ans[2000003];int tot;
    void add(int x,int y,int id,int r){//x,y表示连接的点 id表示正在加入第i条边 r表示权值 
    	node*q=a[r];// q表示所有的 权值为r的边
    	//q[x].id 表示当前x 的边的编号
    	//q[x].to 表示当前边指向的点  
    	if(q[x].id&&q[x].to==y){//相当于 两个点 之间连了 两条边 都要删掉 
    		depend[q[x].id]=depend[id]=0;//当前正在加入的边 和 之前该点对应的边 的依靠 为0 
    		ans[id]=1;ans[q[x].id]=q[y].d;//当前边ans 设为 1 之前边 ans 设为 y的上一条边的 方向 
    		q[x].id=q[y].id=0;//把他们的id 设为 0 相当于删边 
    		return;
    	}
    	int flag=1;
    	if(q[x].id){//如果 x 之前有边 
    		flag=0;
    		depend[q[x].id]=tot;// 那么x之前的边 依靠于新边 
    		rev[q[x].id]=q[x].d;//rev 对于x来说 他之前边的方向 与 其指向相同 
    		//而在实际计算中后面对ans 的计算中 其实是取反了的84行 
    		//因为对于q[x].id这条边来说 他与新加入的边的关系 相同的
    		//若 d==1 则相当于之前的边是指向 x的 
    		//若 新边的方向为 0 那么 这一条边的方向不变
    		//否则 会改变
    		//建议手玩一下 
    		q[x].id=0;//把x 之前的边 删了 
    		x=q[x].to;//将x指向 之前边指向的另一个点 
    	}
    	//与 x同理 
    	if(q[y].id){
    		flag=0;
    		depend[q[y].id]=tot; 
    		rev[q[y].id]=q[y].d^1; //这里与x刚好相反 
    		q[y].id=0;
    		y=q[y].to;
    	}
    	q[x].to=y;q[y].to=x;//互相 成为 对方到达的点 
    	q[x].d=1;q[y].d=0;//钦定方向 默认 从 x -> y的 方向  
    	if(flag)q[x].id=q[y].id=id; //他们的 id 相当于 当前加入的边 
    	else{
    		q[x].id=q[y].id=depend[id]=tot++;//将他们的 id 设为 新点 并且 将他们的依靠 设为新边 
    		//至于关于depend的疑惑 实际在 38 和 42行就已经处理过了 
    	}
    	//相当于 如果 flag == 0 就先当于 加边之后有环了  所以可以将xy对应的之前的边以及当前加入的边 依靠在新边上 
    }
    int vis[2000003];
    void work(int u){
    	int x=u,t=0;
    	vis[x]=1;
    	//t是权值  x是点 a[t][x]相当于 x点在权值t下 对应的唯一一条边 
    	//这里相当于从边权为1的边开始走 
    	while(a[t][x].id){
    		ans[a[t][x].id]=a[t][x].d;//先 将当前边的ans暂且的设为该边本身的方向 
    		if(vis[a[t][x].to])return;//如果出现环了 就返回 因为继续走下去 他还是个环。
    		// 不用担心ans没更新完 因为主函数里面 是一个for 循环 
    		vis[a[t][x].to]=1;
    		x=a[t][x].to;t^=1;
    	}
    	//这里相当于从边权为2的边开始走 
    	x=u;t=1;
    	while(a[t][x].id){
    		ans[a[t][x].id]=a[t][x].d^1;
    		if(vis[a[t][x].to])return;
    		vis[a[t][x].to]=1;
    		x=a[t][x].to;t^=1;
    	}
    }
    signed main(){
    	n=in;m=in;tot=m+1;
    	for(int i=1;i<=m;i++){
    		int a=in;int b=in;int c=in;
    		add(a,b,i,c-1);//第i条边 对应c-1的权值 连接的是a,b 
    	}
    	for(int i=0;i<n;i++)if(!vis[i])work(i);
    	for(int i=tot;i>0;i--){
    		if(depend[i])ans[i]=ans[depend[i]]^rev[i];//rev 如果为1 就要取反 否则 就不取反 
    	}
    	for(int i=1;i<=m;i++)cout<<ans[i];
    	return 0;
    } 
    
  • 相关阅读:
    Url Rewrite IIS 配置
    GridView”的控件 必须放在具有 runat=server 的窗体标记内 “错误提示”
    C#运算符优先级
    Web.config 文件中的 system.webServer
    类型“System.Data.Objects.DataClasses.EntityObject”在未被引用的程序集中定义。
    商城产品分类设计思路
    Jquery几秒自动跳转
    MVC 的 视图中 @section 是什么作用?
    C#异常性能影响
    VSS错误:The Sourcesafe Web service cannot be accessed at the specified address
  • 原文地址:https://www.cnblogs.com/mendessy/p/11722859.html
Copyright © 2020-2023  润新知