• 题解 noip2018模拟测试赛(三十三)


    传送门

    ConvexScore

    题目分析

    神奇组合题

    题目中这个 (m−left| S ight|)​ 相当于求凸多边形内顶点外其他点的数量

    观察发现这个 (2^{m−left| S ight|})​​​ 十分奇怪,考虑它有什么特殊的含义

    我们发现,这个 (2^{m−left| S ight|})​ 代表凸多边形内除顶点外所有点都有选与不选两种状态

    思考后发现答案好像就是能组成的多边形的数量

    容斥一下,多边形的数量即为所有点集数量减去不能组成多边形的点集的数量

    所有点集数量就是 (2^n) ,不能组成多边形的点集的数量就是包含 (0,1,2)​ 个点的点集数量与多点共线的点集数量

    包含 (0,1,2) 个点的点集数量就是 (C_n^0+C_n^1+C_n^2) ,多点共线的点集数量也很好求,我们枚举线段的两端,再枚举在这条线段上的点的数量 (cnt) ,那么在这条线段上的点都有选和不选两种状态,不能全部不选(这样就只有两个点了),所以这条线段的贡献就是 (2^{cnt}-1)

    注意特判 (n<3) 的情况

    代码

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int mod=998244353;
    int n,x[205],y[205];
    long long fpow(long long x,int y) {
    	long long res=1;
    	while(y) {
    		if(y&1)res=res*x%mod;
    		x=x*x%mod;
    		y>>=1;
    	}
    	return res;
    }
    double slope(int i,int j) {
    	if(x[i]==x[j])return -1e18;
    	return (double)(y[i]-y[j])/(x[i]-x[j]);
    }
    int main() {
    	scanf("%d",&n);
    	for(int i=1; i<=n; i++) {
    		scanf("%d%d",&x[i],&y[i]);
    	}
    	if(n<3) {
    		printf("0");
    		return 0;
    	}
    	long long ans=(fpow(2,n)-1-n-n*(n-1)/2+mod)%mod;
    	for(int i=1; i<=n; i++) {
    		for(int j=i+1; j<=n; j++) {
    			int cnt=0;
    			for(int k=j+1; k<=n; k++) {
    				if(slope(i,k)==slope(k,j))cnt++;
    			}
    			ans=(ans-fpow(2,cnt)+1+mod)%mod;
    		}
    	}
    	printf("%lld",ans);
    	return 0;
    }
    

    Poor Turkeys

    题目分析

    枚举点对 ((x,y))​​​ ,表示询问鸡 (x)​​​ 和鸡 (y)​​​​ 能否同时存活

    我们发现,若鸡 (x)​​​ 想要存活,那么对于第 (i)​​ 次吃鸡活动 ((x,z))​​ (即所有 (a_i=x)(b_i=x) 的吃鸡活动),鸡 (z) 必死无疑,且在前 (i-1) 次吃鸡活动中鸡 (z)​​​ 不能死去

    同理,对于第 (jleft(1le j<i ight))​ 次吃鸡活动 ((z,z_2))​ ,鸡 (z_2)​ 必死无疑,且在前 (j-1)​ 次吃鸡活动中鸡 (z_2)​ 不能死去

    依此类推,直到前 (i-1) 次活动中没有与 (z) 有关的吃鸡活动时搜索结束

    (t_u)​​​​​​​ 为编号为 (u)​​​​​​​ 的鸡在第 (t_u)​​​​​​​ 次吃鸡活动时必死无疑,且在前 (t_u-1)​​​​​​​ 次吃鸡活动中鸡 (u)​​​​​​​ 不能死去

    分别对鸡 (x)​ 和鸡 (y)​ 进行搜索,当搜索到鸡 (u)​ 时如果发现 (t_u)​ 已有值且不为当前值时矛盾,鸡 (x)​ 和鸡 (y)​​ 不能同时存活,否则鸡 (x) 和鸡 (y)​ 能同时存活

    时间复杂度 (O(n^2m))​ ,但似乎卡不满

    考虑预处理,时间复杂度可以优化到 (O(nm+n^3)) ,稳过

    代码

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #define inf 0x3f3f3f3f
    using namespace std;
    int n,m;
    struct edge {
    	int to,nxt,val;
    } e[200005];
    int tot=-1,head[405];
    void addedge(int u,int v,int w) {
    	e[++tot].to=v;
    	e[tot].val=w;
    	e[tot].nxt=head[u];
    	head[u]=tot;
    }
    int t[405][405];
    int die[405];
    bool vis[405];
    void dfs(int rt,int u,int fa) {
    	vis[u]=true;
    	for(int i=head[u]; ~i; i=e[i].nxt) {
    		if((i^1)==fa)continue;
    		int v=e[i].to,w=e[i].val;
    		if(w<t[rt][u]) {
    			if(t[rt][v]==0)t[rt][v]=w;
    			else if(t[rt][v]!=w)die[rt]=1;
    			if(!vis[v])dfs(rt,v,i);
    		}
    	}
    }
    bool check(int x,int y) {
    	if(die[x]||die[y])return false;
    	for(int i=1; i<=n; i++) {
    		if(t[x][i]&&t[y][i]) {
    			if(t[x][i]!=t[y][i])return false;
    		}
    	}
    	return true;
    }
    int main() {
    	memset(head,-1,sizeof(head));
    	scanf("%d%d",&n,&m);
    	for(int i=1; i<=m; i++) {
    		int u,v;
    		scanf("%d%d",&u,&v);
    		addedge(u,v,i);
    		addedge(v,u,i);
    	}
    	for(int i=1; i<=n; i++) {
    		memset(vis,0,sizeof(vis));
    		t[i][i]=m+1;
    		dfs(i,i,-1);
    	}
    	int ans=0;
    	for(int i=1; i<=n; i++) {
    		for(int j=i+1; j<=n; j++) {
    			if(check(i,j))ans++;
    		}
    	}
    	printf("%d",ans);
    	return 0;
    }
    

    Pustynia

    题目思路

    有技巧的差分约束题

    弄清题意后,很容易想到这是一道差分约束题,然而直接建边 (O(n^3))​ 明显爆炸,考虑优化

    采用线段树优化建图,将 (k)​ 个点连向 (k+1)​ 个区间,区间用线段树优化分成 (logn)​ 个区间,大的区间再向小的区间连

    (O(n^2logn)) 仍会爆炸,使用一个常见的trick,新建一个中转节点, 将 (k) 个点连向这个中转节点,边权为一,将这个中转节点连向 (k+1)​ 个区间,边权为 (0) ,这样就能轻易做到 (O(nlogn))

    发现这样一个图如果存在环显然是 NIE 的,因此我们只用在有向无环图上进行操作,直接拓扑排序即可,不用最短路

    代码

    #include<iostream>
    #include<cstdio>
    #include<vector>
    #include<queue>
    using namespace std;
    int n,m1,m2,a[600005],a2[600005];
    int d[600005];
    struct edge {
    	int to,nxt,val;
    } e[10000005];
    int tot,head[600005];
    void addedge(int u,int v,int w) {
    	d[v]++;
    	e[++tot].to=v;
    	e[tot].val=w;
    	e[tot].nxt=head[u];
    	head[u]=tot;
    }
    int cnt,id[400005];
    void build(int u,int l,int r) {
    	if(l==r) {
    		id[u]=l;
    		return;
    	}
    	id[u]=++cnt;
    	int mid=(l+r)>>1;
    	build(u<<1,l,mid);
    	build(u<<1|1,mid+1,r);
    	addedge(id[u],id[u<<1],0);
    	addedge(id[u],id[u<<1|1],0);
    }
    void update(int u,int l,int r,int x,int y,int v) {
    	if(x>y)return;
    	if(x<=l&&r<=y) {
    		addedge(v,id[u],0);
    		return;
    	}
    	int mid=(l+r)>>1;
    	if(x<=mid)update(u<<1,l,mid,x,y,v);
    	if(y>mid)update(u<<1|1,mid+1,r,x,y,v);
    }
    bool bfs() {
    	queue<int>q;
    	for(int i=1; i<=cnt; i++) {
    		a[i]=1e9;
    		if(d[i]==0) {
    			if(a2[i])a[i]=a2[i];
    			q.push(i);
    		}
    	}
    	while(!q.empty()) {
    		int u=q.front();
    		q.pop();
    		for(int i=head[u]; i; i=e[i].nxt) {
    			int v=e[i].to,w=e[i].val;
    			if(a2[v]==0) {
    				a[v]=min(a[v],a[u]-w);
    				if(a[v]==0)return false;
    			} else {
    				if(a[u]-w>=a2[v])a[v]=a2[v];
    				else return false;
    			}
    			d[v]--;
    			if(d[v]==0) {
    				q.push(v);
    			}
    		}
    	}
    	for(int i=1; i<=cnt; i++) {
    		if(d[i])return false;
    	}
    	return true;
    }
    int main() {
    	scanf("%d%d%d",&n,&m1,&m2);
    	for(int i=1; i<=m1; i++) {
    		int x,y;
    		scanf("%d%d",&x,&y);
    		a2[x]=y;
    	}
    	cnt=n;
    	build(1,1,n);
    	for(int i=1; i<=m2; i++) {
    		int l,r,k;
    		scanf("%d%d%d",&l,&r,&k);
    		cnt++;
    		int last=l;
    		for(int j=1; j<=k; j++) {
    			int now;
    			scanf("%d",&now);
    			addedge(now,cnt,1);
    			update(1,1,n,last,now-1,cnt);
    			last=now+1;
    		}
    		update(1,1,n,last,r,cnt);
    	}
    	if(bfs()) {
    		printf("TAK
    ");
    		for(int i=1; i<=n; i++) {
    			printf("%d ",a[i]);
    		}
    	} else printf("NIE");
    	return 0;
    }
    
  • 相关阅读:
    普通变量和数组作为函数参数的区别
    2.1
    SQL NULL 值
    SQL ALTER TABLE 语句
    SQL CHECK 约束
    SQL LEFT JOIN 关键字
    SQL JOIN
    SQL Alias(别名)
    SQL 通配符
    从暴力中解脱,
  • 原文地址:https://www.cnblogs.com/ezlmr/p/15099580.html
Copyright © 2020-2023  润新知