zoukankan      html  css  js  c++  java
  • 2021 省选联考 Day 1 意识流题解【二分答案 双指针 差分约束 bitset kosaraju】

    卡牌游戏

    洛谷 P7514

    题意

    (n) 张牌,正反面各有一数字 (a_i,b_i)。初始时所有牌正面朝上。你可以选择至多 (m) 张牌翻转,使得朝上的数字的极差最小。(nleq 10^6)

    输入已经按照 (a_i) 排序。

    题解

    显然最优解一定是取一段连续 (a_i) 不翻转,剩下的翻转。于是先处理 (b_i) 的前、后缀最值。二分答案,讨论最小值是 (a_i) 的左端、在左边翻转的部分还是在右边翻转的部分。假的。因为“连续的一段 (a_i)” 不一定是最长的或最短的。

    我们把 (a_i,b_i) 混起来排序,枚举左端点,取尽可能短的一段满足:

    • 每个位置都有个 (a)(b) 在范围内;
    • (a) 的总量至少是 (n-m)
    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e6+10;
    int a[N],b[N],n,m,u[N],us,s;
    struct C{int v,i,u;}c[N*2];
    int main(){
    	scanf("%d%d",&n,&m); 
        for(int i=0;i<n;i++)scanf("%d",a+i),c[i]=C{a[i],i,1};
        for(int i=0;i<n;i++)scanf("%d",b+i),c[n+i]=C{b[i],i,0};
        sort(c,c+n*2,[&](C a,C b){ return a.v<b.v; });
        int ans=0x7f7f7f7f;
        for(int l=0,r=-1;l<n*2;l++){
    		while(s<n-m||us<n){
    			r++;
    			if(r>=n*2)goto e;
    			if(!u[c[r].i])++us;
    			++u[c[r].i];
    			s+=c[r].u;
    		}
    		ans=min(ans,c[r].v-c[l].v);
    		s-=c[l].u;
    		--u[c[l].i];
    		if(!u[c[l].i])--us;
    	}
    	e:
    	cout<<ans;
    }
    

    矩阵游戏

    洛谷 P7515

    题意

    有一 (n imes m) 的矩阵 (a_{i,j}),每个数在 (0)(10^6) 间。给出 (b_{i,j}=a_{i,j}+a_{i+1,j}+a_{i,j+1}+a_{i+1,j+1}(1leq i<n, 1leq j<m)),构造 (a),或输出无解。(n,mleq 300)(10) 组数据。

    题解

    先设 (a_{n,j})(a_{i,m})(0)。接着建点分别表示 (pm a_{n,j}(1leq j<m))(a_{n,m}pm a_{i,m}(1leq i<n))(a_{n,m})(0),正负号取决于 (m-j,n-i) 的奇偶性。通过连边表示原矩阵每个位置的数的范围限制,跑差分约束。SPFA 需要一些玄学优化。

    垃圾样例让我多测不清空、(n,m) 弄反以及各种出锅。

    #include<bits/stdc++.h>
    using namespace std;
    int getint(){
        int ans=0,f=1;
        char c=getchar();
        while(!isdigit(c)){
            if(c=='-')f=-1;
            c=getchar();
        }
        while(isdigit(c)){
            ans=ans*10+c-'0';
            c=getchar();
        }
        return ans;
    }
    #define ll long long
    const int N=610,M=310*310*4;
    struct bian{
    	int l,e,n;
    };
    bian b[M];
    int s[N],tot=0;
    void add(int x,int y,int z){
    	tot++;
    	b[tot].l=z;
    	b[tot].e=y;
    	b[tot].n=s[x];
    	s[x]=tot;
    }
    
    int n,m;
    ll dis[N];bool inq[N];
    int cnt[N];
    ll a[N/2][N/2],c[N/2][N/2];
    
    bool spfa(int u){
    	memset(dis,0x3f,sizeof(dis));
    	memset(cnt,0,sizeof(cnt));
    	memset(inq,0,sizeof(inq));
    	deque<int>q;
    	q.push_back(u);dis[u]=0;
    	while(q.size()){
    		int t=q.front();q.pop_front();inq[t]=0;
    		++cnt[t];if(cnt[t]>n+m+4)return 1;
    		for(int i=s[t];i;i=b[i].n){
    			int v=b[i].e;
    			if(dis[v]>dis[t]+b[i].l){
    				dis[v]=dis[t]+b[i].l;
    				if(!inq[v]){
    					if(b[i].l<0)q.push_front(v);
    					else q.push_back(v);
    				}
    				inq[v]=1;
    			}
    		}
    	}
    	return 0;
    }
    int main(){
    	freopen("matrix.in","r",stdin);
    	freopen("matrix.out","w",stdout);
    	int T=getint();
    	while(T--){
    		n=getint(),m=getint();
    		memset(b,0,sizeof(b));
    		memset(s,0,sizeof(s));
    		tot=0;
    		for(int i=1;i<n;i++)
    			for(int j=1;j<m;j++)
    				c[i][j]=getint();
    		for(int i=1;i<=n;i++)a[i][m]=0;
    		for(int i=1;i<=m;i++)a[n][i]=0;
    		for(int i=n-1;i;i--)
    			for(int j=m-1;j;j--)
    				a[i][j]=(c[i][j]-a[i+1][j]-a[i][j+1]-a[i+1][j+1]);
    		for(int i=1;i<n;i++)
    			for(int j=1;j<m;j++){
    				if(((n-i)&1)^((m-j)&1)){
    					add(j,i+300,-a[i][j]+1e6);
    					add(i+300,j,a[i][j]); 
    				}else{
    					add(i+300,j,-a[i][j]+1e6);
    					add(j,i+300,a[i][j]);
    				}
    			}
    		for(int i=1;i<m;i++){
    			if((m-i)&1)add(601,i,0),add(i,601,1e6);
    			else add(601,i,1e6),add(i,601,0);
    		}
    		for(int i=1;i<n;i++){
    			if((n-i)&1)add(602,300+i,1e6),add(300+i,602,0);
    			else add(602,300+i,0),add(300+i,602,1e6);
    		}
    		add(601,602,1e6);
    		add(602,601,0);
    		if(spfa(601))puts("NO");
    		else{
    			a[n][m]=dis[602];
    			for(int i=1;i<m;i++){
    				if((m-i)&1)a[n][i]=-dis[i];
    				else a[n][i]=dis[i];
    			}
    			for(int i=1;i<n;i++){
    				if((n-i)&1)a[i][m]=dis[300+i]-dis[602];
    				else a[i][m]=-dis[300+i]+dis[602];
    			}
    			for(int i=n-1;i;i--)
    				for(int j=m-1;j;j--)
    					a[i][j]=(c[i][j]-a[i+1][j]-a[i][j+1]-a[i+1][j+1]);
    			puts("YES");
    			for(int i=1;i<=n;i++){
    				for(int j=1;j<=m;j++)
    					printf("%d ",a[i][j]);
    				printf("
    ");
    			}
    		}
    	}
    }
    
    
    

    图函数

    洛谷 P7516

    题意

    对于一张 (n) 个点 (m) 条边的有向图 (G)(顶点从 (1 sim n) 编号),定义函数 (f(u, G))

    1. 初始化返回值 (cnt = 0),图 (G' = G)
    2. (1)(n) 按顺序枚举顶点 (v),如果当前的图 (G') 中,从 (u)(v) 与从 (v)(u) 的路径都存在,则将 (cnt + 1),并在图 (G') 中删去顶点 (v) 以及与它相关的边。
    3. (2) 步结束后,返回值 (cnt) 即为函数值。

    现在给定一张有向图 (G),求 (h(G) = f(1, G) + f(2, G) + cdots + f(n, G)) 的值。

    更进一步地,记删除(按输入顺序给出的)第 (1)(i) 条边后的图为 (G_i)(1 le i le m)),请你求出所有 (h(G_i)) 的值。

    (nleq 10^3)(mleq 2 imes 10^5)

    题解

    第二步可以变为直接删除枚举到的所有点,因为不强连通的点删不删都是一回事。

    于是问题变为:对于每个 (i,j),统计保留点 ([i,n]) 和边 ([0,j]) 得到的图中 (i) 所在连通块大小。与 (i) 强连通可以看作 (i) 能到它、它能到 (i),于是转而考虑正图、反图上 (i) 能够到达的点。(也可以考虑成 kosaraju)

    枚举 (i);将边按照编号从大到小加入,并用边来尝试更新 (i) 到终点的【最小边权尽可能大】的路径,从如果更新成功就从它开始 D(B)FS,继续更新其他点,bitset 优化。每个点的贡献范围是一个前缀。

    复杂度 (O(dfrac{n^3]{omega}+nm))

    #include<bits/stdc++.h>
    using namespace std;
    int getint(){
        int ans=0,f=1;
        char c=getchar();
        while(!isdigit(c)){
            if(c=='-')f=-1;
            c=getchar();
        }
        while(isdigit(c)){
            ans=ans*10+c-'0';
            c=getchar();
        }
        return ans;
    }
    #define ll long long
    #define ull unsigned long long
    const int N=1010,M=2e5+10;
    int n,m,qaqaq;
    int lb[1<<16];
    inline void flip(ull *a,int x){
    	a[x>>6]^=1ull<<(x&63);
    }
    inline bool get(ull *a,int x){
    	return (a[x>>6]>>(x&63))&1;
    }
    int lowbit(ull *a,ull *b,int x=0){
    	int y=x>>6;
    	while(y<N/64+2&&!(a[y]&b[y]))++y;
    	if(y>=N/64+2)return -1;
    	ull z=a[y]&b[y];
    	if(z&((1ull<<16)-1))return lb[z&((1ull<<16)-1)]+(y<<6);
    	if(z&((1ull<<32)-1))return lb[(z>>16)&((1ull<<16)-1)]+16+(y<<6);
    	if(z&((1ull<<48)-1))return lb[(z>>32)&((1ull<<16)-1)]+32+(y<<6);
    	return lb[z>>48]+48+(y<<6);
    }
    
    struct gragh{
    	ull b[N][N/64+3];
    	int c[N][N];
    	int u[M],v[M],tot=0;
    	void add(int x,int y){
    		tot++;u[tot]=x;v[tot]=y;
    		c[x][y]=tot;
    	}
    	int dis[N];
    	ull uvis[N/64+3];
    	void init(int i){
    		memset(dis,0,sizeof(dis));
    		memset(b,0,sizeof(b));
    		memset(uvis,-1,sizeof(uvis));
    		memset(uvis,0,sizeof(ull)*max(i/64-1,0));
    		dis[i]=m+1;for(int j=i/64*64;j<=i;j++)flip(uvis,j);
    	}
    	int q[N],top;
    	inline void add_(int l,int i){
    		int u=this->u[i],v=this->v[i];
    		flip(b[u],v);
    		if(dis[u]&&!dis[v]){
    			dis[v]=i;flip(uvis,v);
    			q[top++]=v;
    			while(top){
    				int t=q[--top];
    				for(int v=lowbit(uvis,b[t]);~v;v=lowbit(uvis,b[t],v)){
    					++qaqaq;
    					dis[v]=i,q[top++]=v,flip(uvis,v);
    				}
    			}
    		}
    	}
    } g,h;
    
    int ans[M];
    list<int>b;
    int main(){
    //	freopen("graph.in","r",stdin);
    //	freopen("graph.out","w",stdout);
    	for(int i=0;i<16;i++)for(int j=1<<i;j<1<<16;j+=2<<i)lb[j]=i;
    	n=getint(),m=getint();
    	for(int i=1;i<=m;i++){
    		int u=getint(),v=getint();
    		g.add(u,v);
    		h.add(v,u);
    	}
    	for(int i=m;i;i--)b.push_back(i);
    	for(int i=1;i<=n;i++){
    //		cerr<<">>>> "<<i<<endl;
    		g.init(i),h.init(i);
    		for(auto j=b.begin();j!=b.end();){
    //			cerr<<"> "<<g.u[*j]<<" "<<g.v[*j];
    			g.add_(i,*j);
    			h.add_(i,*j);
    			if(g.u[*j]==i||g.v[*j]==i){
    				auto k=j;j++;b.erase(k);
    			}else j++;
    		}
    //		cerr<<endl;
    //		for(int j=i;j<=n;j++)cerr<<"> "<<g.dis[j];cerr<<endl;
    //		for(int j=i;j<=n;j++)cerr<<"> "<<h.dis[j];cerr<<endl;
    		for(int j=i;j<=n;j++)ans[min(g.dis[j],h.dis[j])]++;
    //		qaqaq=0;
    	}
    	for(int i=m+1;i;--i)ans[i]+=ans[i+1];
    	for(int i=1;i<=m+1;i++)printf("%d ",ans[i]);
    }
    
    
    
    知识共享许可协议
    若文章内无特别说明,公开文章采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。
  • 相关阅读:
    06.章节页面接口开发
    05.课程主页面三个接口开发
    python高级(六)——用一等函数实现设计模式
    python高级(五)—— python函数(一等对象)
    python高级(四)—— 文本和字节序列(编码问题)
    python高级(三)—— 字典和集合(泛映射类型)
    python高级——目录
    python高级(二)—— python内置序列类型
    python高级(一)—— python数据模型(特殊方法)
    python实现百度地图API获取某地址的经纬度
  • 原文地址:https://www.cnblogs.com/wallbreaker5th/p/14655103.html
Copyright © 2011-2022 走看看