Andrew Stankevich's Contest #8 Solution

Andrew Stankevich's Contest #8

Solution

Problem A: NonptimalAssignments

Problem B: Cryptography

Problem C: FibonacciSubsequence

Problem D: Hexagonand Rhombic Dominoes

Problem E: StrangeLimit

Problem F: LittleMammoth

Problem G: NetworkWars

Problem H: OilDeal

Problem I: Bishopson a Toral Board

July 23th,2013 by chlxyd,xioumu


Problem A: Nonptimal Assignments

         构造一个矩阵,使得题目中所给的贪心不能得到正确答案。

Solution

Tag:构造

    121

        012

        001

     构造乱搞题,可行的做法比如对角线以下全是0,从对角线开始从1递增,最后f[1][n]变成1就可以了。方法还有非常多。

/*
 * Author:  chlxyd
 * Created Time:  2013/7/19 12:41:14
 * File Name: A.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define clr(x) memset( x , 0 , sizeof(x) )
#define sz(v) ((int)(v).size())
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define repf(i, a, b) for (int i = (a); i <= (b); ++i)
#define repd(i, a, b) for (int i = (a); i >= (b); --i)
#define clrs( x , y ) memset( x , y , sizeof(x) )
int n ;
int a[110][110] ;
int main(){
    while ( scanf("%d" , &n ) == 1 ) {
        repf( i , 1 , n ) {
            repf( j , 1 , i - 1 ) a[i][j] = 0 ;
            repf( j , i , n ) 
                a[i][j] = j - i + 1 ;
        }
        a[1][n] = 1 ;
        repf( i , 1 , n ) { 
            repf( j , 1 , n ) {
                if ( j != 1 ) printf(" " ) ;
                printf("%d" , a[i][j] ) ;
            }
            printf("\n") ;
        }
        printf("\n") ;
    }
}


 

Problem B: Cryptography

         10W2*2的矩阵,10W次询问,每次问ab矩阵的乘积。

Solution

Tag:数据结构

   如果给的不是矩阵是树的话很快就能想到用线段树去解决,换成矩阵也是一样的,只是把数的乘法改成矩阵的乘法。

 

/*
 * Author:  chlxyd
 * Created Time:  2013/7/19 13:53:57
 * File Name: B.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define clr(x) memset( x , 0 , sizeof(x) )
#define sz(v) ((int)(v).size())
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define repf(i, a, b) for (int i = (a); i <= (b); ++i)
#define repd(i, a, b) for (int i = (a); i >= (b); --i)
#define clrs( x , y ) memset( x , y , sizeof(x) )
int n , R , m ;
struct matrix {
    int a[2][2] ;
    void clrr() {
        clr(a) ;
    }
    matrix operator * ( const matrix & q ) const {
        matrix ret ;
        ret.a[0][0] = a[0][0] * q.a[0][0] + a[0][1] * q.a[1][0] ;
        ret.a[0][1] = a[0][0] * q.a[0][1] + a[0][1] * q.a[1][1] ;
        ret.a[1][0] = a[1][0] * q.a[0][0] + a[1][1] * q.a[1][0] ;
        ret.a[1][1] = a[1][0] * q.a[0][1] + a[1][1] * q.a[1][1] ;
        repf( i , 0 , 1 )
            repf( j , 0 , 1 ) 
                ret.a[i][j] %= R ;
        return ret ;
    }
    void show() {
        printf("%d %d\n" , a[0][0] , a[0][1] ) ;
        printf("%d %d\n" , a[1][0] , a[1][1] ) ;
    }
};
struct treetype {
    matrix a ;
    int l , r ;
}tree[210000] ;
void up( int i ) {
    tree[i].a = tree[i*2].a * tree[i*2+1].a ;
}
matrix find( int i , int l , int r ) {
    if ( tree[i].l == l && tree[i].r == r ) return tree[i].a ;
    int mid = ( tree[i].l + tree[i].r ) / 2 ;
    if ( r <= mid ) return find( i * 2 , l , r ) ;
    else if ( l > mid ) return find( i * 2 + 1 , l , r ) ;
    else return find( i * 2 , l , mid ) * find( i * 2 + 1 , mid + 1 , r ) ;
}
void maketree( int i , int l , int r ) {
    tree[i].l = l ; tree[i].r = r ; tree[i].a.clrr() ;
    if ( l == r ) {
        repf( x , 0 , 1 ) 
            repf( y , 0 , 1 )
                scanf("%d" , &tree[i].a.a[x][y] ) ; 
        return ;
    }
    int mid = ( l + r ) / 2 ;
    maketree( i * 2 , l , mid ) ;
    maketree( i * 2 + 1 , mid + 1 , r ) ;
    up(i) ;
}
int main(){
    bool first = true ;
    while ( scanf("%d %d %d" , &R , &n , &m ) == 3 ) {
        if ( !first ) puts("" ) ;
        maketree( 1 , 1 , n ) ;
        repf( i , 1 , m ) {
            int l , r ;
            if ( i != 1 ) puts("") ;
            scanf("%d %d" , &l , &r ) ;
            if ( l > r ) swap( l , r ) ;
            find( 1 , l , r ).show() ;
        }
        first = false ;
    }
}

Problem C: Fibonacci Subsequence

         有一个长度为3000的序列,问序列中的满足斐波拉契性质的序列最长是多少。

Solution

Tag:动态规划,数据结构

首先把数离散一下,这样我们就只有3000个数,dp[i][j]表示当前位置i,上一个j的最长长度,枚举两个位置ij,则dp[i][hash(a[j])]= max( dp[j][hash(a[i]-a[j])]+1)。这题会卡logn,所以hash手写或者用hash_map

 

/*
 * Author:  chlxyd
 * Created Time:  2013/7/19 16:54:11
 * File Name: C (2).cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include <utility>
#include <ext/hash_map>

using namespace std;
using namespace __gnu_cxx;
const double eps(1e-8);
typedef long long lint;
#define clr(x) memset( x , 0 , sizeof(x) )
#define sz(v) ((int)(v).size())
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define repf(i, a, b) for (int i = (a); i <= (b); ++i)
#define repd(i, a, b) for (int i = (a); i >= (b); --i)
#define clrs( x , y ) memset( x , y , sizeof(x) )
hash_map<int,int> mp ;
int n , top ;
int a[3100] ;
short int f[3010][3010] ;
int jlx , jly ;
int mod = 1000007 ;
bool bj[3100] ;
int flag[3010] ;
int hhash( int a ) {
    if ( mp[a]  )return mp[a] ;
    return mp[a] = ++ top ;
}
int main(){
    bool ff = true ;
    while ( scanf("%d" , &n ) == 1 ) {
        top = 0 ;
        clr(bj) ;
        mp.clear() ;
        if (!ff) puts("") ;
        repf( i , 1 , n )
            repf( j , 1 , n ) f[i][j] = 0 ;
        ff = false ;
        repf( i , 1 , n ) {
            scanf("%d" , &a[i] ) ;
            hhash(a[i]) ;
        }
        if ( n == 1 ) {
            printf("1\n") ;
            printf("%d\n" , a[1] ) ;
            continue ;
        }
        int ans = 0 ;
        repf( j , 1 , n ) flag[j] = hhash(a[j]) ;
        repf( i , 1 , n ) {
            repf( j , 1 , i - 1 ) {
                int p = flag[j] ;
                f[i][p] = max( f[i][p] , (short int)2 ) ;
                hash_map<int,int>::iterator tmp = mp.find(a[i] - a[j]);
                if ( tmp == mp.end() ) 
                    continue ;
                int k = tmp->second ;
                if ( f[i][p] - f[j][k] - 1 < 0 ) 
                    f[i][p] = f[j][k] + 1 ;
                if ( ans < f[i][p] ) {
                    ans = f[i][p] ;
                    jlx = i ; jly = j ;
                }
            }
        }
        if ( ans == 0 )  {
            ans = 2 ;
            jlx = 1 ;
            jly = 2 ;
        }
        bj[jlx] = true ; bj[jly] = true ;
        printf("%d\n" , ans ) ;
        repd( i , jly - 1 , 1 ) {
            if ( a[i] == a[jlx] - a[jly] ) {
                bj[i] = true ;
                jlx = jly ;
                jly = i ;
            }
        }
        bool first = true ;
        repf( i , 1 , n ) {
            if ( bj[i] ) {
                if ( !first ) printf(" ") ;
                first = false ;
                printf("%d" , a[i] ) ;
            }
        }
        printf("\n") ;
    }
}

 

Problem D: Hexagon and Rhombic Dominoes

         给一个边长为n正六边形,用三角形划分了,问用题中给的方块去铺,有多少种铺满方式。

Solution

Tag:动态规划

盗个watashi blog的图。


图中可以很清楚的看出,如果按照列来分的话,行的状态是非常清楚的,然后按照这个状态表示来进行转移就行了,到了中间的位置对于当前方案数在另外一边也一定能达到这么多方案,所以答案累加方案数的平方。然后打表什么的随便写了。

 附做表程序

 

/*
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define clr(x) memset( x , 0 , sizeof(x) )
#define sz(v) ((int)(v).size())
#define rep(i, n) for (long long i = 0; i < (n); ++i)
#define repf(i, a, b) for (long long i = (a); i <= (b); ++i)
#define repd(i, a, b) for (long long i = (a); i >= (b); --i)
#define clrs( x , y ) memset( x , y , sizeof(x) )
long long top ;
long long n ;
long long dp[20][1<<20] ;
long long jl[20][2] ;

void dfs( long long i , long long s , long long val , long long ii ) {
    if ( i == top + 1 ) {
        dp[ii][s] += val ;
        return ;
    }
    repf( j , jl[i][0] , jl[i][1] ) {
        dfs( i + 1 , s + ( 1 << j ) , val , ii ) ;
    }
}
int main(){
    scanf("%lld" , &n );
    rep( i , n + 1 ) dp[n+1][1<<i] = 1 ;
    repf( i , n + 2 , n + n ) {
        rep( j , 1 << i ) {
            long long s = j ;
            if ( dp[i-1][s] == 0 ) continue ;
            s <<= 1 ;
            long long num = i - n - 1 ;
            top = 0 ;
            long long last = 0 ;
            rep( k , i ) {
                if ( s & ( 1 << k ) ) {
                    jl[++top][0] = last ;
                    jl[top][1] = k - 1 ;
                    last = k ;
                }
            }
            jl[++top][0] = last ;
            jl[top][1] = i - 1 ;
            dfs( 1 , 0 , dp[i-1][j] , i ) ;
        }
   	}
    long long ans = 0 ;
    rep( j , 1 <<(n+n) ) {
        ans += dp[n+n][j] * dp[n+n][j] ;
    }
    cout<<ans<<endl;
}

*/
/*
 * Author:  chlxyd
 * Created Time:  2013/7/19 20:21:36
 * File Name: D1.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define clr(x) memset( x , 0 , sizeof(x) )
#define sz(v) ((int)(v).size())
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define repf(i, a, b) for (int i = (a); i <= (b); ++i)
#define repd(i, a, b) for (int i = (a); i >= (b); --i)
#define clrs( x , y ) memset( x , y , sizeof(x) )
long long f[80];
int main(){
    f[1] = 2;
    f[2] = 20;
    f[3] = 980;
    f[4] = 232848;
    f[5] = 267227532;
    f[6] = 1478619421136;
    f[7] = 39405996318420160;
    bool first = true ;
    int n ;
    while ( scanf("%d" , &n ) == 1 ) {
        if ( !first ) puts("") ;
        first = false ;
        printf("%lld\n" , f[n] ) ;
    }
}

Problem E: Strange Limit

         f(a) = a^f(a) mod m!的值

Solution

Tag:数学

         M的阶层和a为质数都是无用的东西。

     欧拉定理的内容是:如果a和n互质,那么aφ(n)=1(modn);对于任意a, n和较大的b,有ab=aφ(n)+b mod φ(n)(mod n)。

     设b = m!,那么对于(a^f(a)) % b,套进公式则等于a^(φ(b) + b mod φ(b))mod b, 而a^b mod φ(b) 同样套入公式等于a^(φ(φ(b) )+ b modφ(φ(b))) modφ(b), 就这一直递归下去φ(φ(φ.. φ(b)…))最终会等于1.

     这样就可以递归求解了。

 

/*
 * Author:  chlxyd
 * Created Time:  2013/7/19 15:50:31
 * File Name: E.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define clr(x) memset( x , 0 , sizeof(x) )
#define sz(v) ((int)(v).size())
#define rep(i, n) for (lint i = 0; i < (n); ++i)
#define repf(i, a, b) for (lint i = (a); i <= (b); ++i)
#define repd(i, a, b) for (lint i = (a); i >= (b); --i)
#define clrs( x , y ) memset( x , y , sizeof(x) )

lint n, m, mod;

lint mypow(lint a, lint b, bool &flag) {
    lint res = 1;
    while (b != 0) {
        if (b % 2 == 1) {
            res *= a;
            if (res >= mod)
                flag = true;
            res %= mod;
        }
        a *= a;
        if (a >= mod) flag = true;
        a %= mod;
        b >>= 1;
    }
    return res;
}

int main(){
    bool first = false;
    while (scanf("%lld%lld", &n, &m) == 2) {
        if (first) printf("\n");
        if (n == 2 && m == 2) {
            printf("0\n");
            first = true;
            continue;
        }
        mod = 1;
        repf (i, 1, m)
            mod *= i;
        bool flag = false;
        lint ans = 1;
        int h = 200;
        while (--h > 0) {
            ans = mypow(n, ans, flag);
        }
        printf("%lld\n", ans);
        first = true;
    }     
    return 0;
}

 

Problem F: Little Mammoth

         求圆与长方形的面积交

Solution

Tag:计算几何

         可以用几何中求多边形面积的方法来求,求出所有圆与长方形形的交点,然后算出三角或者扇形的有向面积,相加求绝对值即可。

         这个watashi博客中的图很直观。


        

这里有求线段与圆的交点的介绍:http://www.thecodeway.com/blog/?p=1873

 

/*
 * Author:  xioumu
 * Created Time:  2013/7/21 15:24:58
 * File Name: F.cpp
 * solve: F.cpp
 */
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<map>
#include<set>
#include<iostream>
#include<vector>
#include<queue>

using namespace std;
#define sz(v) ((int)(v).size())
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define repf(i, a, b) for (int i = (a); i <= (b); ++i)
#define repd(i, a, b) for (int i = (a); i >= (b); --i)
#define clr(x) memset(x,0,sizeof(x))
#define clrs( x , y ) memset(x,y,sizeof(x))
#define out(x) printf(#x" %d\n", x)
#define sqr(x) ((x) * (x))
typedef long long lint;

const int maxint = -1u>>1;
const double pi = acos(-1.0);
const double eps = 1e-8;

int sgn(const double &x) {  return (x > eps) - (x < -eps); }

struct point {
    double x, y;
    point (double _x = 0, double _y = 0) : x(_x), y(_y) {
    }
    double operator * (const point &p) const {
        return (x * p.y) - (y * p.x);
    }
    point operator - (const point &p) const {
        return point(x - p.x, y - p.y);
    }
    point operator + (const point &p) const {
        return point(x + p.x, y + p.y);
    }
    void output() {
        printf("%.3f %.3f\n", x, y);
    }
};

point operator * (const double &l, const point &p) {
    return point(l * p.x, l * p.y);
}

vector<point> p;

void gao(point u, point v, double r) {
    double a = sqr(v.x - u.x) + sqr(v.y - u.y);
    double b = 2 * ((v.x - u.x) * u.x + (v.y - u.y) * u.y);
    double c = sqr(u.x) + sqr(u.y) - sqr(r);
    double det = b * b - 4 * a * c;
    p.push_back(u);
    if (det < 0) {
        return;
    }
    double t1 = (-b + sqrt(det)) / 2 / a;
    double t2 = (-b - sqrt(det)) / 2 / a;
    //printf("%f %f\n", t1, t2);
    if (t1 > t2) 
        swap(t1, t2);
    if (sgn(t1) > 0 && sgn(t1 - 1) < 0) {
        p.push_back(u + t1 * (v - u));
    }
    if (sgn(t2) > 0 && sgn(t2 - 1) < 0 && sgn(t1 - t2) != 0) {
        p.push_back(u + t2 * (v - u));
    } 
}

double tri(point a, point b) {
    return abs( (a * b) / 2 );
}

double sec(point a, point b, double r) {
    double ang1 = atan2(a.y, a.x);
    double ang2 = atan2(b.y, b.x);
    if (ang1 < 0) ang1 = 2 * pi + ang1;
    if (ang2 < 0) ang2 = 2 * pi + ang2;
    double dang = abs(ang2 - ang1);
    if (dang > pi) 
        dang = 2 * pi - dang;
    return r * r * dang / 2;
}

//double sec(const point& u, const point& v, double r) {
	//double t = atan2(v.y, v.x) - atan2(u.y, u.x);
	//while (t > pi) {	// WA!!
		//t -= 2 * pi;
	//}
	//while (t < -pi) {
		//t += 2 * pi;
	//}
	//return abs(r * r * t) / 2;
//}


int main() {
    bool blank = false;
    double x, y, r, x1, y1, x2, y2;
    while (scanf("%lf%lf%lf", &x, &y, &r) == 3) {
        if (blank) puts("");
        blank = 1;
        scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
        x1 -= x;
        y1 -= y;
        x2 -= x;
        y2 -= y;
        
        p.clear();
        gao(point(x1, y1), point(x1, y2), r);
        gao(point(x1, y2), point(x2, y2), r);
        gao(point(x2, y2), point(x2, y1), r);
        gao(point(x2, y1), point(x1, y1), r);
        
        double ans = 0;
        p.push_back(p.front());
        rep (i, sz(p) - 1) {
            if (sgn( hypot((p[i].x + p[i + 1].x) / 2, (p[i].y + p[i + 1].y) / 2) - r) >= 0) {
                ans += sgn(p[i] * p[i + 1]) * sec(p[i], p[i + 1], r);
                //printf("sec : %f\n",  sgn(p[i] * p[i + 1]) * sec(p[i], p[i + 1], r));
            }
            else {
                ans += sgn(p[i] * p[i + 1]) * tri(p[i], p[i + 1]);
                //printf("tri : %f\n",  sgn(p[i] * p[i + 1]) * tri(p[i], p[i + 1]));
            } 
            //p[i].output();
        }
        printf("%.11f\n", abs(ans)); 
    }
    return 0;
}

Problem G: Network Wars

         给一个图,让你选择一些边,使得这些边是用最小的代价使得起点与终点分开。代价的定义是选择的边的权值和除以边数

Solution

         Tag:网络流,分数规划

         二分答案,求最小割,对于每一次二分,假设答案为x,把所有的边减去x,若边权小于0,加入割边只会减小答案的值,所以一定在割边中。对剩下的边,求最小割,若所有割边(包括权值小于0的边)的权值和小于0,则x还可以更小,否则x需要更大。具体的分数规划的证明在 胡伯涛的《最小割模型在信息学竞赛中的应用》有证明。

         注意,这里的最小割需要用实数来求。

 

/*
 * Author:  xioumu
 * Created Time:  2013/7/20 23:09:25
 * File Name: F_xioumu.cpp
 * solve: F_xioumu.cpp
 */
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<map>
#include<set>
#include<iostream>
#include<vector>
#include<queue>

using namespace std;
#define sz(v) ((int)(v).size())
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define repf(i, a, b) for (int i = (a); i <= (b); ++i)
#define repd(i, a, b) for (int i = (a); i >= (b); --i)
#define clr(x) memset(x,0,sizeof(x))
#define clrs( x , y ) memset(x,y,sizeof(x))
#define out(x) printf(#x" %d\n", x)
#define sqr(x) ((x) * (x))
typedef long long lint;

const int maxint = -1u>>1;
const double eps = 1e-8;
const int maxn = 400 + 10;

int sgn(const double &x) {  return (x > eps) - (x < -eps); }

struct Graph {
    struct Adj {
        int v, b, id;
        double c;
        Adj(int _v, double _c, int _id, int _b) :
            v(_v), c(_c), id(_id), b(_b){}
        Adj(){}
    };
    int n, S, T, h[maxn], cnt[maxn];
    vector<Adj> adj[maxn];
    void clear() {
        for (int i = 0; i < n; i++) {
            adj[i].clear();
        }
        n = 0;
    }
    void insert(int u, int v, double c, int id, int d = 0) {
        n = max(n, max(u, v) + 1);
        adj[u].push_back(Adj(v, c, id, adj[v].size()));
        adj[v].push_back(Adj(u, c * d, id, adj[u].size() - 1));
    }
    double maxflow(int _S, int _T) {
        S = _S, T = _T;
        fill(h, h + n, 0);
        fill(cnt, cnt + n, 0);
        double flow = 0;
        while (h[S] < n) {
            flow += dfs(S, maxint);
        }
        return flow;
    }
    double dfs(int u, double flow) {
        if (u == T) {
            return flow;
        }
        int minh = n - 1;
        double ct = 0;
        for (vector<Adj>::iterator it = adj[u].begin(); sgn(flow) > 0 && it != adj[u].end(); ++it) {
            if (sgn(it->c) > 0) {
                if (h[it->v] + 1 == h[u]) {
                    double k = dfs(it->v, min(it->c, flow));
                    if (sgn(k) > 0) {
                        it->c -= k;
                        adj[it->v][it->b].c += k;
                        flow -= k;
                        ct += k;
                    }
                    if (h[S] >= n) {
                        return ct;
             }
                }
                minh = min(minh, h[it->v]);
            }
        }
        if (sgn(ct) > 0) {
            return ct;
        }
        if (--cnt[h[u]] == 0) {
            h[S] = n;
        }
        h[u] = minh + 1;
        ++cnt[h[u]];
        return 0;
    }
}G, G2;

int n, m;
int S, T;

bool gao(double x) {
    double sum = 0;
    G2 = G;
    rep (i, n) {
        rep (k, sz(G2.adj[i])) {
            G2.adj[i][k].c -= x;
            if (sgn(G2.adj[i][k].c) < 0) { 
                sum -= G2.adj[i][k].c;
                G2.adj[i][k].c = 0;
            }
        }
    }
    sum /= 2;
    double ans = G2.maxflow(S, T);
    ans -= sum; 
    if (sgn(ans) <= 0) return true;
    else return false;
}

vector<int> ans;
int v[maxn], va[maxn];
void dfs(int w) {
    if (v[w]) return;
    v[w] = 1;
    rep (i, sz(G2.adj[w])) {
        int j = G2.adj[w][i].v;
        if (sgn(G2.adj[w][i].c) > 0) {
            dfs(j);
        }
    }
}

void mark_ans(double mans) {
    memset(v, 0, sizeof(v));
    dfs(S);
    ans.clear();
    memset(va, 0, sizeof(va));
    rep (i, n) {
        //if (v[i] == 0) continue;
        rep (k, sz(G.adj[i])) {
            int j = G.adj[i][k].v;
            //printf("%d %d %.2f %d %d\n", i, j, G2.adj[i][k].c, v[i], v[j]);
            if (va[G.adj[i][k].id]) continue;
            if ((v[i] == 1 && v[j] == 0) || sgn(G.adj[i][k].c - mans) < 0) {
                ans.push_back(G.adj[i][k].id);
                va[G.adj[i][k].id] = 1;
            }
        }
    }
}

int main() {
    bool blank = false;
    while (scanf("%d%d", &n, &m) == 2) {
        if (blank) puts("");
        blank = true;
        G.clear();
        double l = 0, r = 0;
        rep (i, m) {
            int x, y, z;
            scanf("%d%d%d", &x, &y, &z);
            x--, y--;
            G.insert(x, y, z, i + 1, 1);        
            r += z;
        }
        double mans = r;
        S = 0, T = n - 1;
        rep (i, 100) {
            double mid = (l + r) / 2.0;
            //printf("%f %f\n", l, r);
            if (gao(mid)) {
                r = mid;
                mans = mid;
            }
            else l = mid;
        }
        //out("test");
        gao(mans);
        mark_ans(mans);
        printf("%d\n", sz(ans));
        rep (i, sz(ans)) {
            if (i != 0) printf(" ");
            printf("%d", ans[i]);
        }
        printf("\n");
        //printf("%f\n", mans);
    } 
    return 0;
}

Problem H: Oil Deal

         给一个图,让你选择一些边删了,要求删除后的图要是连通图。删边有各种的代价,求在一定代价下最多能删多少边。

Solution

Tag贪心,最小生成树

         求最大生成树,除了这个生成树里的边都是可以删的。于是乎把剩下的边排序从代价小的取,能取多少取多少即可。

         证明:假设取了最大生成树里的边A后更优,代替A的放进生成树中的边B一定比边A代价高。但这样的话B会比A优先选进最大生成树中,所以矛盾。

 

/*
 * Author:  chlxyd
 * Created Time:  2013/7/19 14:17:32
 * File Name: H.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define clr(x) memset( x , 0 , sizeof(x) )
#define sz(v) ((lint)(v).size())
#define rep(i, n) for (lint i = 0; i < (n); ++i)
#define repf(i, a, b) for (lint i = (a); i <= (b); ++i)
#define repd(i, a, b) for (lint i = (a); i >= (b); --i)
#define clrs( x , y ) memset( x , y , sizeof(x) )

const lint maxn = 100000 * 2 + 10;

struct node {
    lint x, y, z, id;
    node (const lint _x = 0, const lint _y = 0, const lint _z = 0, const lint _id = 0) :
        x(_x), y(_y), z(_z), id(_id){
        }
};

vector<node> e, can;
vector<lint > pans;
lint fa[maxn], n, m, sum;

lint find(lint w) {
    if (fa[w] == w) return w;
    lint k = find(fa[w]);
    fa[w] = k;
    return k;
}

bool cmp(const node &a, const node &b) {
    return a.z > b.z;
}

bool cmp2(const node &a, const node &b) {
    return a.z < b.z;
}

int main(){
    bool flag = false;
    while (scanf("%lld%lld%lld", &n, &m, &sum) == 3) {
        if (flag) printf("\n");
        e.clear();
        can.clear();
        rep (i, m) {
            lint x, y, z;
            scanf("%lld%lld%lld", &x, &y, &z);
            x--, y--;
            e.push_back(node(x, y, z, i + 1)); 
        }
        sort(e.begin(), e.end(), cmp);
        rep (i, n) 
            fa[i] = i;
        rep (i, m) {
            lint r = find(e[i].x);
            lint w = find(e[i].y);
            if (r != w) {
                fa[r] = w;
            }
            else {
                can.push_back(e[i]);
            }
        } 
        
        sort(can.begin(), can.end(), cmp2);
        pans.clear();
        rep (i, sz(can)) {
            if (sum < can[i].z) break;
            pans.push_back(can[i].id);
            sum -= can[i].z;
        }
        printf("%lld\n", sz(pans));
        rep (i, sz(pans)) {
            if (i != 0) printf(" ");
            printf("%lld", pans[i]);
        }
        if (sz(pans) != 0) 
            printf("\n");
        flag = true;
    }
    return 0;
}

Problem I: Bishops on aToral Board

         有一个n*m的棋盘,棋盘边缘是循环的,棋子可以往一个方向斜着走任意步。

Solution

Tag贪心,最小生成树

         答案就是gcd(n,m)。

         囧,还不会证明。

 

/*
 * Author:  chlxyd
 * Created Time:  2013/7/19 13:18:32
 * File Name: I.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define clr(x) memset( x , 0 , sizeof(x) )
#define sz(v) ((int)(v).size())
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define repf(i, a, b) for (int i = (a); i <= (b); ++i)
#define repd(i, a, b) for (int i = (a); i >= (b); --i)
#define clrs( x , y ) memset( x , y , sizeof(x) )

const int maxn = 100000 + 10;
char s1[maxn], s2[maxn];

int main(){
    bool flag = false;
    while (scanf("%s%s", s1, s2) == 2) {
        if (flag) printf("\n");
        //printf("%s\n%s\n", s1, s2);
        int l1 = strlen(s1);
        int l2 = strlen(s2);
        int d1 = s1[l1 - 1] - '0';
        int d2 = s2[l2 - 1] - '0';     
        if ((l1 == 1 && d1 == 0) || (l2 == 1 && d2 == 0))
            printf("0\n");
        else if (d1 % 2 == 0 && d2 % 2 == 0) {
            printf("2\n");
        }
        else printf("1\n");
        flag = true;
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值