• Codeforces Round #284 (Div. 2)


    It is my first Codeforces round!

    Problem C

    题目大意:一个平面内有一些无限长的直线,把平面分成了若干块,从一块走一步可以走到与它有公共边的另一块,但是只有公共点不能一步走过去。给定两个在块内部的点,问从S点到T点最少走几步。

    题目分析:由于每步只能跨越公共边,不能从两直线交点处跨越,所以一步只能越过 S 与 T 之间的一条直线,那么答案就是 S 与 T 之间有多少条直线(即 S 与 T 在这些直线的两侧)。判断 S 与 T 在直线 l 两侧 :  l : ax + by + c = 0        (a*Sx + b*Sy + c) 与 (a*Tx + b*Ty + c) 异号。

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    
    using namespace std;
    
    const int MaxN = 300 + 5;
    
    int Sx, Sy, Tx, Ty, n, Ans, a, b, c;
    
    typedef long long LL;
    
    LL N1, N2;
    
    int main() 
    {
    	scanf("%d%d%d%d", &Sx, &Sy, &Tx, &Ty);
    	scanf("%d", &n);
    	Ans = 0;
    	for (int i = 1; i <= n; ++i) {
    		scanf("%d%d%d", &a, &b, &c);
    		N1 = (LL)a * (LL)Sx + (LL)b * (LL)Sy + (LL)c;
    		N2 = (LL)a * (LL)Tx + (LL)b * (LL)Ty + (LL)c;
    		if (N1 > 0) N1 = 1; else N1 = -1;
    		if (N2 > 0) N2 = 1; else N2 = -1;
    		if (N1 * N2 < 0) ++Ans;
    	}
    	printf("%d
    ", Ans);
    	return 0;
    }
    

    Problem E

    题目大意:

      给定一个序列 A[n] ,还有一些实数对 (i, j) ,满足 i + j 为奇数。每次可以进行一次操作:选取一个实数对 (i, j),如果 A[i] 和 A[j] 不互质,就可以 ++Ans,然后将他们同除以一个大于 1 的公因子。这些实数对可重复利用。问 Ans 最多可以多大。

    题目分析:

      题目中的实数对为 (i, j) 满足 i + j 为奇数,所以 i 与 j 一个是奇数,一个是偶数。那么所有的实数对就相当于在每对 i,j 之间的连边,这样就组成一个二分图,只有下标为偶数的数和下标为奇数的数可能连边,奇数与奇数,偶数与偶数不能连边。

      这个题的操作描述中的网络流气息十分明显...那么就是求最大流,下面我们来建图:

      如果各种不同的质因数一起考虑会很困难,我想了好久最终弃了... 后来不得不求助于黄学长。

      但是,每个质因子之间是互不影响的,如果我们每次只考虑一个质因数,那就简单多了。

      对于一个质因数 x ,枚举所有的 A[i],如果 A[i] 中没有 x 这个因子,就跳过,否则分情况建边:若 i 为奇数,就连边 S -> i, 容量为 A[i] 中 x 的指数;如果 i 为偶数,就连边 i -> T, 容量为 A[i] 中 x 的指数。

      对于每个实数对,我们从奇数向偶数连边,容量 INF。

      这样求最大流就可以求出用这个质因子可以贡献的答案。

      因此,我们每次处理一个质因数,每次重新建图,每次跑一遍最大流,累加到答案中。

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    
    using namespace std;
    
    const int MaxX = 100 + 5, LogN = 32 + 5, MaxN = 100 + 5, MaxM = 300 + 5, INF = 0x3fffffff;
    
    int n, m, MaxFlow, Ans, S, T, Tot, a, b;
    int A[MaxX], d[MaxN], Num[MaxN], B[MaxN][3];
    
    inline int gmin(int a, int b) {return a < b ? a : b;}
    inline int gmax(int a, int b) {return a > b ? a : b;}
    
    struct Edge
    {
    	int v, w;
    	Edge *Next, *Other;
    } E[MaxM * 2], *P = E, *Point[MaxN], *Last[MaxN];
    
    inline void AddEdge(int x, int y, int z) {
    	Edge *Q = ++P; ++P;
    	P -> v = y; P -> w = z;
    	P -> Next = Point[x]; Point[x] = P; P -> Other = Q;
    	Q -> v = x; Q -> w = 0;
    	Q -> Next = Point[y]; Point[y] = Q; Q -> Other = P;
    }
    
    int DFS(int Now, int Flow) {
    	if (Now == T) return Flow;
    	int ret = 0;
    	for (Edge *j = Last[Now]; j; j = j -> Next) {
    		if (j -> w && d[Now] == d[j -> v] + 1) {
    			Last[Now] = j;
    			int p = DFS(j -> v, gmin(j -> w, Flow - ret));
    			ret += p; j -> w -= p; j -> Other -> w += p;
    			if (ret == Flow) return ret;
    		}
    	}
    	if (d[S] >= Tot) return ret;
    	if (--Num[d[Now]] == 0) d[S] = Tot;
    	++Num[++d[Now]];
    	Last[Now] = Point[Now];
    	return ret;
    }
    
    void Solve(int x) {
    	memset(E, 0, sizeof(E)); P = E;
    	memset(Point, 0, sizeof(Point));
    	for (int i = 1; i <= n; ++i) {
    		int Cnt = 0;
    		while (A[i] % x == 0) {
    			++Cnt;
    			A[i] /= x;
    		}
    		if (Cnt == 0) continue;
    		if (i & 1) AddEdge(S, i, Cnt);
    		else AddEdge(i, T, Cnt);
    	}
    	for (int i = 1; i <= m; ++i) 
    		AddEdge(B[i][0], B[i][1], INF);
    	MaxFlow = 0;
    	memset(d, 0, sizeof(d));
    	memset(Num, 0, sizeof(Num)); Num[0] = Tot;
    	for (int i = 1; i <= Tot; ++i) Last[i] = Point[i];
    	while (d[S] < Tot) MaxFlow += DFS(S, INF);
    	Ans += MaxFlow;
    }
    
    int main() 
    {
    	scanf("%d%d", &n, &m);
    	Ans = 0;
    	for (int i = 1; i <= n; ++i) scanf("%d", &A[i]);
    	for (int i = 1; i <= m; ++i) {
    		scanf("%d%d", &B[i][0], &B[i][1]);
    		if (B[i][1] & 1) swap(B[i][0], B[i][1]);
    	}
    	S = n + 1; T = S + 1; Tot = T;
    	for (int i = 1; i <= n; ++i) {
    		int SQ = (int)sqrt(A[i] * 1.0);
    		for (int j = 2; j <= SQ; ++j) 
    			if (A[i] % j == 0) Solve(j);
    		if (A[i] > 1) Solve(A[i]);
    	}
    	printf("%d
    ", Ans);
    	return 0;
    }
    

      

  • 相关阅读:
    Eclipse 中生成帮助文档 (javadoc) 迎客
    网管利器:七大免费网络工具 迎客
    oracle 11g 学习笔记 10_27
    oracle 11g 学习笔记 10_29
    oracle 11g学习笔记 2012_10_22
    oracle 11g 学习笔记 2012_10_25(2)
    oracle 11g 学习笔记 10_26
    oracle 11g 学习笔记 2012_10_24(1)
    oracle 11g 学习笔记2012_10_23(2)
    oracle 11g 学习笔记 2012_10_25(a)
  • 原文地址:https://www.cnblogs.com/JoeFan/p/4185204.html
Copyright © 2020-2023  润新知