zoukankan      html  css  js  c++  java
  • csp-s模拟48,49 Tourist Attractions,养花,画作题解

    题面:https://www.cnblogs.com/Juve/articles/11569010.html

    Tourist Attractions:

    暴力当然是dfs四层

    优化一下,固定两个点,答案就是这两个点的度数减一相乘,在枚举第三点,减去三元环的情况

    三元环可以用bitset优化

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<bitset>
    #define re register
    #define int long long
    using namespace std;
    const int MAXN=1505;
    int n,ans=0,du[MAXN];
    bool mp[MAXN][MAXN];
    char ch[MAXN];
    bitset<MAXN>b[MAXN],t;
    signed main(){
    	scanf("%lld",&n);
    	for(re int i=1;i<=n;++i){
    		b[i].reset();
    		scanf("%s",ch+1);
    		for(re int j=1;j<=n;++j){
    			if(ch[j]=='1'){
    				b[i].set(j,1);
    				mp[i][j]=1;
    				++du[i];
    			}
    		}
    	}
    	t.reset();
    	for(int x=1;x<=n;++x){
    		for(int y=1;y<=n;++y){
    			if(y==x) continue;
    			if(mp[x][y]!=1) continue;
    			ans+=(du[x]-1)*(du[y]-1);
    			t=b[x]&b[y];
    			ans-=t.count();
    		}
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    养花:

    考场上只有暴力了。。。

    考虑到k只有1e5,我们考虑预处理出每一个k时的情况

    我们考虑分块,预处理出每一个块内%k的最大值,查询时大段直接统计块内的,小段暴力

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int block=1e3;
    const int MAXN=1e5+5;
    const int N=1e5+2;
    const int MAXM=1e2+5;
    int n,m,a[MAXN],f[MAXN],blo[MAXN],num,mx[MAXM][MAXN];
    signed main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;++i) scanf("%d",&a[i]),blo[i]=(i-1)/block;
    	num=(n-1)/block;
    	for(int i=0;i<=num;++i){
    		memset(f,0,sizeof(f));
    		int l=i*block+1,r=min(n,(i+1)*block);
    		for(int j=l;j<=r;++j) f[a[j]]=a[j];
    		for(int j=1;j<=N;++j) f[j]=max(f[j],f[j-1]);
    		for(int j=1;j<=N;++j){
    			for(int k=0;k<=N;k+=j){
    				mx[i][j]=max(mx[i][j],f[min(k+j-1,N)]-k);
    			}
    		}
    	}
    	while(m--){
    		int l,r,k,ans=0;
    		scanf("%d%d%d",&l,&r,&k);
    		for(int i=blo[l]+1;i<blo[r];++i) ans=max(ans,mx[i][k]);
    		for(int i=l;i<=min(r,(blo[l]+1)*block);++i) ans=max(ans,a[i]%k);
    		for(int i=max(l,blo[r]*block+1);i<=r;++i) ans=max(ans,a[i]%k);
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    

    画作:

    有一个性质:在画的时候每次修改的点都是上一次修改的点的子集

    不难证明猜到一个这样的结论: 存在一种最优方案使得每次操作的区
    域是上一次的子集且颜色与上一次相反.
    考虑归纳证明, 记 S 为当前所有操作区域的并, T 为接下来一步的操作
    区域, 我们有:
    1. T 与 S 有交的情况一定可以转化成 T 被 S 包含的情况.
    2. T 与 S 交集为空时, 可以找一个连接 S 和 T 的集合 M 并操作 S ∪
    T ∪ M , 并将之前的所有操作连接到更外的层以及外层的连接部分同时
    操作, 特殊处理最外层和第二层的情况.
    3. T 被 S 包含时, T 落在某个完整区域内时等价于情况二, 否则一定连
    接若干个同色块, 这些块可以同时处理, 步数一定不会更劣.
    知道这个结论就比较好做了, 我们可以枚举最后被修改的区域, 这时答
    案就是将同色边边权当作 0, 异色边边权当作 1 后距离这个点最远的黑色点
    的距离, 对所有点取最小值即可.

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    using namespace std;
    int n,m,mp[55][55],ans=0x7fffffff;
    char ch[55];
    int dx[4]={1,-1,0,0};
    int dy[4]={0,0,1,-1};
    int calc(int i,int j){return (i-1)*m+j;}
    bool vis[55*55];
    int dis[55*55];
    priority_queue< pair< pair<int,int>,pair<int,int> > >pq;
    inline int dij(int st,int pp,int qq){
    	memset(dis,0x3f,sizeof(dis));
    	dis[st]=0;
    	memset(vis,0,sizeof(vis));
    	pq.push(make_pair(make_pair(-dis[st],st),make_pair(pp,qq)));
    	while(!pq.empty()){
    		pair< pair<int,int>,pair<int,int> > pa=pq.top();
    		pq.pop();
    		if(vis[pa.first.second]) continue;
    		vis[pa.first.second]=1;
    		int x=pa.second.first,y=pa.second.second;
    		for(int i=0;i<4;++i){
    			int p=x+dx[i],q=y+dy[i];
    			if(p<1||p>n||q<1||q>m) continue;
    			int w=!(mp[x][y]==mp[p][q]);
    			int v=calc(p,q);
    			if(dis[v]>dis[pa.first.second]+w){
    				dis[v]=dis[pa.first.second]+w;
    				pq.push(make_pair(make_pair(-dis[v],v),make_pair(p,q)));
    			}
    		}
    	}
    	int res=0;
    	for(int i=1;i<=n;++i){
    		for(int j=1;j<=m;++j){
    			if(mp[i][j]==1) res=max(res,dis[calc(i,j)]);
    		}
    	}
    	return res;
    }
    signed main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;++i){
    		scanf("%s",ch+1);
    		for(int j=1;j<=m;++j){
    			mp[i][j]=ch[j]-'0';
    		}
    	}
    	for(int i=1;i<=n;++i){
    		for(int j=1;j<=m;++j){
    			ans=min(ans,dij(calc(i,j),i,j));
    		}
    	}
    	printf("%d
    ",ans+1);
    	return 0;
    }
    
  • 相关阅读:
    将view添加到地图覆盖物
    将eclipse的编码改成UTF-8,默认是GBK
    Android调用系统关机与重启功能
    Android中preference标签的使用
    linux中convert用法
    RookeyFrame在线新增模块
    RookeyFrame2.0发布,UI重构
    Rookey.Frame v1.0 视频教程发布了
    Rookey.Frame企业级快速开发框架开源了
    RookeyFrame模块初始化
  • 原文地址:https://www.cnblogs.com/Juve/p/11569002.html
Copyright © 2011-2022 走看看