Andrew Stankevich's Contest #10 Solution

 

Andrew Stankevich's Contest #10

Solution

Problem A: Brackets

Problem B: Dividinga Chocolate

Problem C: ThermalDeath of the Universe

Problem D: EquationsSystem

Problem E: Fool'sGame

Problem F: Lottery

Problem G: TwoPipelines

Problem H: RegularWords

August 2nd,2013 by chlxyd,xioumu

Problem A: Brackets

给两种括号的组成的序列,让输出最长括号合法的连续子串是。

 

Solution

Tag:其他

先标记标记出哪些对括号是合法的。

重头枚举,遇到’(‘和’[‘放进栈中。遇到’]’和’)’看张顶是不是与其对于的括号,若是标记的对括号的位置,若不是,那栈里的元素都不会合法,把栈清空。

最后找最长的一段连续的被标记子串就是答案。

/*
 * Author:  xioumu
 * Created Time:  2013/7/29 12:39:37
 * File Name: A.cpp
 * solve: A.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 = 200000 + 10;

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

char s[maxn];
int n;
int sta[maxn], top;
int v[maxn], f[maxn];

int main() {
    while (scanf("%s", s) == 1) {
        n = strlen(s);
        int top = 0;
        memset(v, 0, sizeof(v));
        rep (i, n) {
            if (s[i] == '(' || s[i] == '[') {
                sta[++top] = i;
            } 
            else {
                if (s[i] == ')' || s[i] == ']') {
                    if (top == 0) continue;
                    if ((s[i] == ')' && s[sta[top]] == '(') || 
                        (s[i] == ']' && s[sta[top]] == '[')) {
                        //printf("%d %d\n", i, sta[top]);
                        v[i] = 1;
                        v[sta[top]] = 1;
                        //printf("%d %d\n", sta[top], v[5]);
                        top--;
                    }
                    else top = 0;
                }
            }
        }
        //rep (i, n)
            //printf("%d", v[5]);
        //puts("");
        int ans = 0;
        memset(f, 0, sizeof(f));
        rep (i, n) {
            if (i != 0) f[i] = f[i - 1];
            if (v[i] == 1) {
                f[i]++;
            }
            else f[i] = 0;
            if (f[i] > f[ans]) {
                ans = i;
            }
        } 
        repf (i, ans - f[ans] + 1, ans) {
            //printf("%d\n", i);
            printf("%c", s[i]);
        }
        printf("\n\n");
    } 
    return 0;
}


 

Problem B: Dividinga Chocolate

有一块n*m的巧克力,按照题目给的方法分,问最多能吃到多少块。

 

Solution

Tag:数学,结论

第一步枚举分n还是m,答案取大者。

对于分一个数n,如果这个数是斐波拉契数,那么显然可以把其分成只剩一块,如果不是菲波拉契数,找到其最大的菲波拉契数的因子x,那么可以把其分至只剩n/x块,这样最优。

如果题目改成不能大块连续减去2小块面积,出现这种情况就停止而不是非法的话,可以三分第一次分的位置。

 

/*
 * Author:  chlxyd
 * Created Time:  2013/7/29 14:09:45
 * 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) )
long long f[200] ;
long long cal( long long n ) {
    repd( i , 80 , 3 ) {
        if ( ( n % f[i] ) == 0 )
            return n / f[i] ;
    }
    return 0 ;
}
long long solve( long long n , long long m ) {
    int a = cal(n) , b = cal(m) ;
    if ( a == 0 && b == 0 ) return 0;
    if ( a == 0 ) a = n ;
    if ( b == 0 ) b = m ;
    return max( n * m - a * m , n * m - b * n ) ;
}
int main(){
    f[1] = 1 ;f[2] = 1 ;
    long long n , m ;
    repf( i , 3 , 80 ) f[i] = f[i-1] + f[i-2] ;
    while ( scanf("%lld %lld" , &n , &m ) == 2 ) {
        printf("%lld\n" , solve( n , m ) ) ;
        puts("") ;
    }
}

Problem C: hermalDeath of the Universe

一个长度为n的序列,每次取一段区间出来,把区间中数变成这些数平均数,视情况(向上/向下)取整。

 

Solution

Tag:数据结构

很简单的线段树的题目,注意区间和是负数的情况。

 

/*
 * Author:  chlxyd
 * Created Time:  2013/7/29 14:24:06
 * File Name: C.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 (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) )
#define maxn 50000 
struct treetype {
    long long l , r , sum ;
}tree[maxn*4];
long long add[maxn*4] ;
long long n , m ;
long long a[maxn] ;
long long top ;
long long sum ;
long long calc( bool big , long long a , long long b ) {
    if ( a % b == 0 ) return a / b ;
    if ( a > 0 ) {
        if ( big ) return a / b + 1 ;
        return a / b ;
    }
    else {
        if ( big ) return a / b ;
        return a / b - 1 ;
        
    }
}
void pushdown( long long i ) {
    if ( add[i] ) {
        add[i*2] = add[i*2+1] = add[i] ;
        tree[i*2].sum = ( tree[i*2].r - tree[i*2].l + 1 ) * add[i] ;
        tree[i*2+1].sum = ( tree[i*2+1].r - tree[i*2+1].l + 1 ) * add[i] ;
        add[i] = 0 ;
    }
}
void up( long long i ) {
    tree[i].sum = tree[i*2].sum + tree[i*2+1].sum ;
}
long long cal( long long i , long long l , long long r ) {
    if ( l == tree[i].l && r == tree[i].r ) 
        return tree[i].sum ;
    pushdown(i) ;
    long long mid = ( tree[i].l + tree[i].r ) / 2 ;
    if ( r <= mid ) return cal( i * 2 , l , r ) ;
    else if ( l > mid ) return cal( i * 2 + 1 , l ,r ) ;
    else return cal( i * 2 , l , mid ) + cal( i * 2 + 1 , mid + 1 , r ) ;
}
void change( long long i , long long l , long long r , long long c ) {
    if ( tree[i].l == l &&  r == tree[i].r ) {
        add[i] = c ;
        tree[i].sum = ( r - l + 1 ) * c ;
        return ;
    }
    pushdown(i) ;
    long long mid = ( tree[i].l + tree[i].r ) / 2 ;
    if ( r <= mid ) change( i * 2 , l , r , c ) ;
    else if ( l > mid ) change( i * 2 + 1 , l , r , c ) ;
    else {
        change( i * 2 , l , mid , c ) ;
        change( i * 2 + 1 , mid + 1 , r , c ) ;
    }
    up(i) ;
}
void maketree( long long i , long long l , long long r ) {
    tree[i].l = l ; tree[i].r = r ; tree[i].sum = 0 ; add[i] = 0 ;
    if ( l == r ) {
        tree[i].sum = a[++top] ;
        return ;
    }
    long long mid = ( l + r ) / 2 ;
    maketree( i * 2 , l , mid ) ;
    maketree( i * 2 + 1 , mid + 1 , r ) ;
    up(i) ;
}
int main(){
    while ( scanf("%lld %lld" , &n , &m ) == 2 ) {
        sum = 0 ;
        repf( i , 1 , n ) {
            scanf("%lld" , &a[i] ) ;
            sum += a[i] ;
        }
        top = 0 ;
        maketree(1,1,n) ;
        repf( i , 1 , m ) {
            long long a , b ;
            scanf("%lld %lld" , &a , &b ) ;
            if ( a > b ) swap( a , b ) ;
            long long nowsum = cal( 1 , 1 , n ) ;
            long long gsum = cal( 1 , a , b ) ;
            long long cnum = calc( nowsum <= sum , gsum , ( b - a + 1 ) ) ;
            change( 1 , a , b , cnum ) ;
        }
        repf( i , 1 , n ) {
            if ( i != 1 ) printf(" ") ;
            printf("%lld" , cal(1,i,i) ) ;
        }
        puts("") ;
        puts("") ;
    }
}

Problem D: EquationsSystem

求多项式x和y,满足

a1(t)x(t)+b1(t)y(t) = c1(t)

a2(t)x(t)+b2(t)y(t) = c2(t)

其中a,b,c已给出。

 

Solution

Tag:数学,数据结构。

首先自己定义一个多项式类型的数据结构,支持加,减,乘,除。

如果a1b2-a2b1!=0那么多项式有唯一解,通过公式计算。

如果a1=a2且b1=b2,如果c1!=c2无解,否则退化到一个等式,用扩展gcd来求一组解。

如果a1=0且b2=0类似这种情况,原方程退化成两个小一次方程,分别求解。

如果全为0,那么任意解均可。

 

/*
 * Author:  chlxyd
 * Created Time:  2013/7/29 16:08:56
 * File Name: D.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 flag ;
struct poly{
    int a[300] ;
    int l ;
    void clear() {
        clr(a) ;
        l = 1 ;
    }
    bool zero() {
        if ( l == 1 && a[1] == 0 ) return true ;
        return false ;
    }
    bool operator == ( const poly & q ) const {
        if ( l != q.l ) return false ;
        repf( i , 1 , l )
            if ( a[i] != q.a[i] ) return false ;
        return true ;
    }
    poly operator + ( const poly & q ) const {
        poly ret ; ret.clear() ;
        ret.l = max( l , q.l ) ;
        repf( i , 1 , ret.l ) 
            ret.a[i] = q.a[i] ^ a[i] ;
        int tmp = ret.l ;
        ret.l = 1 ;
        repd( i , tmp , 1 ) {
        	if ( ret.a[i] != 0 ) {
	        	ret.l = i ;
	        	break ;
	        }
        }
        return ret ;
    }    
    poly operator - ( const poly & q ) const {
        poly ret ; ret.clear() ;
        ret.l = max( l , q.l ) ;
        repf( i , 1 , ret.l ) 
            ret.a[i] = q.a[i] ^ a[i] ;
        int tmp = ret.l ;
        ret.l = 1 ;
        repd( i , tmp , 1 ) {
        	if ( ret.a[i] != 0 ) {
	        	ret.l = i ;
	        	break ;
	        }
        }
        return ret ;
    }
    poly operator * ( const poly & q ) const {
        poly ret ; ret.clear() ;
        repf( i , 1 , l )
            repf( j , 1 , q.l ) 
                ret.a[i+j-1] ^= a[i] * q.a[j] ;
        repd( i , q.l + l , 1 )
            if ( ret.a[i] != 0 ) {
                ret.l = i ;
                break ;
            }
        return ret ;
    }
    poly operator / ( const poly & q ) const {
        poly ret ; ret.clear() ;
        poly now ; now.clear() ;
        ret.l = l ;
        repf( i , 1 , l ) 
            ret.a[i] = a[i] ;
        flag = false ;
        if ( l == 1 && q.a[1] == 0 ) { 
            ret.clear() ;
            return ret ;
        }
        if ( ret.l < q.l ) {
            flag = true ;
            ret.clear() ; 
            return ret ;
        }
        repd( i , l - q.l + 1 , 1 ) {
            if ( ret.a[i+q.l-1] == 1 ) {
               now.a[i] = 1 ;
               repd( j , i + q.l - 1 , i ) 
                    ret.a[j] ^= q.a[j-i+1] ;
            }
        }
        repd( i , l , 1 ) {
        	if ( now.a[i] != 0 ) {
        		now.l = i ;
        		break ;
        	}
        }
        repf( i , 1 , q.l - 1 ) 
            if ( ret.a[i] != 0 ) {
                flag = true ;
            }
        return now ;
    }
    int readin() {
    	clr(a) ;
        if ( scanf("%d" , &l) != 1 ) return 0 ;
        l ++ ;
        repd( i , l , 1 ) scanf("%d" , &a[i] ) ;
		if ( l == 0 ) l = 1 ;
        return 1 ;
    }
    void show() {
        if ( l == 1 && a[1] == 0 ) puts("-1") ;
        else {
        	printf("%d" , l - 1 ) ;
        	repd( i , l , 1 ) {
            	printf(" %d" , a[i] ) ;
        	}
        	puts("") ;
        }
    }
};
poly a[2] , b[2] , c[2] ;
poly ansx , ansy ;
poly extgcd( poly a , poly b , poly &x , poly &y ) {
    if ( b.zero() ) {
        x.clear() ; x.a[1] = 1 ; y.clear() ;
        return a ;
    }
    poly ret = extgcd( b , a - ( a / b ) * b , x , y ) ;
    poly t = x ; x = y ; y = t - (a / b) * y ;
    return ret ;
}
bool dopoly( poly a , poly b , poly c ) {
    poly x , y ;
    poly gcd = extgcd( a , b , x , y ) ;
    poly c1 = c / gcd ;
    if ( flag ) return false ;
    ansx = x * c1 ; ansy = y * c1 ;
    return true ;
}
bool solve() { 
    if ( a[0].zero() && b[0].zero() && !c[0].zero() ) return false ;
    if ( a[1].zero() && b[1].zero() && !c[1].zero() ) return false ;    
    if ( a[0].zero() && b[0].zero() && c[0].zero() && a[1].zero() && b[1].zero() && c[1].zero() ) return true ;
    if ( a[0].zero() && b[0].zero() && c[0].zero() )
        return dopoly( a[1] , b[1] , c[1] ) ;
    else if (  a[1].zero() && b[1].zero() && c[1].zero() )
        return dopoly( a[0] , b[0] , c[0] ) ; 
    poly D = a[0]*b[1] - a[1]*b[0] ;
    if ( !D.zero() ) {
    	//ansx = c[0] * a[1] - c[1] * a[0];
        ansy = ( c[0]*a[1] - c[1]*a[0] ) / ( a[1]*b[0]-a[0]*b[1]) ;
        if ( flag ) return false ;
        ansx = ( c[0]*b[1] - c[1]*b[0] ) / ( a[1]*b[0]-a[0]*b[1]) ;
        if ( flag ) return false ;
    }
    else {
        if ( !(c[0]*a[1] - c[1]*a[0]).zero() ) return false ;
        if ( !(c[0]*b[1] - c[1]*b[0]).zero() ) return false ;
        bool bj = false ;
        if ( a[0].zero() ) {
            bj = true ;
            ansy = c[0] / b[0] ;
            if (flag ) return false ;
        }
        if ( b[0].zero() ) {
            bj = true ;
            ansx = c[0] / a[0] ;
            if ( flag ) return false ;
        }        
        if ( a[1].zero() ) {
            bj = true ;
            ansx = c[1] / b[1] ;
            if ( flag ) return false ;
        }        
        if ( b[1].zero() ) {
            bj = true ;
            ansx = c[1] / a[1] ;
            if ( flag ) return false ;
        }
        if ( !bj )
            return dopoly(a[0],b[0],c[0]) ;
    }
    return true ;
}
int main(){
	//freopen("D.in","r",stdin);
    while ( a[0].readin() ) {
        b[0].readin() ; c[0].readin() ;
        a[1].readin() ; b[1].readin() ; c[1].readin() ;
            if ( !solve() ) 
                puts("No solution") ;
            else {
                ansx.show() ;
                ansy.show() ;
            }
            puts("") ;
    }
}

Problem E: Fool'sGame

有两个人A和B,每个人各有36张牌,牌有4种花色和9种点数大小。4种花色中有一种是主花色。一张牌x能覆盖另一张牌y,当且仅x的花色与y相同,点数比y大,或者x是主花色而y不是。

现在桌面上有些A已经出的牌。

每一轮,B需要覆盖上一轮A出的所有牌。A需要出之前双方出过 牌中存在的点数的牌,可以出任意张。

B不能覆盖牌的时候B输。

A不能出牌时,A输。

问最后谁胜。

Solution

Tag:博弈,YY,最大匹配

考虑最终B胜利的时候,桌子出现的所有牌的点数,A的这些点数的牌必然B会有对应的牌覆盖,否则B就不会胜利。而桌上出现哪些点数只能是由初始时桌上的牌和B出的牌来决定。也就是说B可以决定桌上存在哪些点数。

所以可以枚举最后桌上出现了哪些点数,然后对于这些点数若A的一张盘能被B的一张牌覆盖就给他们之间连条边。求最大匹配,若所有A的这些点数的牌都能匹配到对应的B的牌,那B就能胜。

若所有情况都匹配不到则A胜。

 

/*
 * Author:  xioumu
 * Created Time:  2013/7/29 19:48:50
 * File Name: E.cpp
 * solve: E.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 int maxn = 1000 + 10;
const double eps = 1e-8;

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

struct node {
    int x, y;
    node(int _x = 0, int _y = 0) : x(_x), y(_y) {
    }
};

int two(int x) {
    return 1 << x;
}

bool bit(int mark, int x) {
    return (mark & (1 << x)) != 0;
}
int n;
int mainy, have[maxn], v[maxn], fa[maxn];
vector<node> a, b;
vector<int> e[maxn];

int getX(char c) {
    if ('0' <= c && c <= '9') return c - '6';
    else if (c == 'T') return 4;
    else if (c == 'J') return 5;
    else if (c == 'Q') return 6;
    else if (c == 'K') return 7;
    else return 8;
}

int getY(char c) {
    if (c == 'S') return 0;
    else if (c == 'C') return 1;
    else if (c == 'D') return 2;
    else if (c == 'H') return 3;
}

void init() {
    clr(have);
    a.clear();
    b.clear();
    char s[10];
    rep (i, n * 2) {
        scanf("%s", s);
        int x = getX(s[0]);
        int y = getY(s[1]);
        if (s[2] == '*')
            have[x] = 1;
        if (i < n)
            a.push_back(node(x, y));
        else b.push_back(node(x, y));
        //printf("%d %d\n", x, y);
    }
    //printf("%d %d\n", sz(a), sz(b));
}

bool xiong(int w) {
    rep (i, sz(e[w])) {
        int j = e[w][i];
        if (!v[j]) {
            v[j] = 1;
            if (fa[j] == -1 || xiong(fa[j])) {
                fa[j] = w;
                return true;
            }     
        }
    }
    return false;
}

bool gao(int mark) {
    int need = 0;
    //rep (i, 9)
        //printf("%d", have[i]);
    //puts("");
    rep (i, 9)
        if ( bit(mark, i) == 0 && have[i])
            return false;
    rep (i, n * 2)
        fa[i] = -1;
    rep (i, 2 * n)
        e[i].clear();
    rep (i, sz(a)) {
        //printf("%d\n", a[i].x);
        rep (j, sz(b)) {
            if (bit(mark, a[i].x) && bit(mark, b[j].x)) {
                //printf("%d %d %d\n", mark, a[i].x, b[j].x);
                if ((a[i].y == b[j].y && a[i].x < b[j].x) ||
                        (a[i].y != mainy && b[j].y == mainy)) {
                    e[i].push_back(j + n);
                    e[j + n].push_back(i);
                }
            } 
        }
        if (bit(mark, a[i].x))
            need++;
    }
    int cnt = 0;
    rep (i, n) {
        clr(v);
        if (xiong(i)) {
            cnt++; 
        }
    }
    //printf("%d %d\n", need, cnt);
    return need == cnt;
}

int main() {
    char ch[5];
    while (scanf("%d%s", &n, ch) == 2) {
        mainy = getY(ch[0]);
        init();
        int ans = 0;
        rep (i, two(9)) {
            if (gao(i)) {
                //printf("%d\n", i);
                ans = 1;
                break;
            }
        }
        if (ans) printf("COVER\n");
        else printf("TAKE\n");
        puts("");
    } 
    return 0;
}

Problem F: Lottery

 N个空位,和一个字符串S长为M,你可以在N个空位中填任意的S中出现过的字符,而且N中填的各个字符个数不能少于S。问你能使从这N个空位中M个字符组成S的最小和最大的概率是多少。

Solution

Tag:贪心,组合

因为答案的分母是固定的,所以只用求最大和最小分子。

假设N个空位中有K个字母i,串S中有W个字母i, 那正好拿出来这些的分子是C(W, K),空位你增加一个字母i的话,分子会变成C(W, K +1) = C(W, K) * (W + 1) / (K – W +1),再增加一个就需要再乘一个(W + 2)/(K – W + 2),通过观察可以发现(W + j) / (K – W + j),这个式子是递减的。

然后先看怎么算最大的分子:

N个空位已经填了M个字符。还剩N – M个空位,每填一个分子都是乘以一个(Wi + j)/(Ki – Wi + j),i是填的字母,j是剩下的N-M个空位中已经填了j个i字母。

因为这个式子随着j变大而变小,所以我们可以枚举每次从i个字母中选个当前这个式子最大的字母出来填上。

然后求最小的分子:

还是这个式子(Wi + j)/(Ki – Wi + j),还剩N – M个空位时,最初Ki都等于Wi。通过观察,发现W越小下降越缓慢,剩下N-M个空位都填最初这个式子的字最小的字母即可。

 

import java.io.*;
import java.math.*;
import java.util.*;

public class Main {
	private static int maxn = 60 + 10;
	private static BigInteger ZERO = new BigInteger("0");
	private static BigInteger ONE = new BigInteger("1");
	
	public static BigInteger gaoMax(int[] have, int n, int m) {
		BigInteger res = ONE;
		int nn = 0;
		int[] mu = new int[maxn];
		int[] zi = new int[maxn];
		for (int i = 0; i < 26; i++) {
			if (have[i] != 0) {
				zi[nn] = have[i] + 1;
				mu[nn] = 1;
				nn++;
			}
		}
		
		for (int i = 0; i < n - m; i++) {
			int k = -1;
			for (int j = 0; j < nn; j++) {
				if (k == -1)
					k = j;
				else {
					if (zi[k] * mu[j] < zi[j] * mu[k])
						k = j;
				}
			}
			res = res.multiply(BigInteger.valueOf(zi[k]));
			res = res.divide(BigInteger.valueOf(mu[k]));
			zi[k]++;
			mu[k]++;
		}
		return res;
	}
	
	public static BigInteger gaoMin(int[] have, int n, int m) {
		BigInteger res = ONE;
		int mmi = 100000;
		int mu = 1, zi = 1;
		for (int i = 0; i < 26; i++) {
			if (have[i] != 0) {
				if (have[i] < mmi) {
					mmi = have[i];
					mu = 1;
					zi = have[i] + 1;
				}
			}
		}
		//System.out.println(zi + " " + mu);
		//System.out.println(n - m);
		for (int i = 0; i < n - m; i++) {
			res = res.multiply(BigInteger.valueOf(zi));
			res = res.divide(BigInteger.valueOf(mu));
			zi++;
			mu++;
		}
		//System.out.println(res);
		return res;
	}
	public static void main(String[] args) {
		Scanner cin = new Scanner(System.in);
		while (cin.hasNextInt()) {
			int m = 0;
			int n = cin.nextInt();
			String s = cin.next();
			int[] have = new int[maxn];
			m = s.length();
			for (int i = 0; i < s.length(); i++) {
				have[s.charAt(i) - 'A']++;
			}
			BigInteger maAns = gaoMax(have, n, m);
			BigInteger miAns = gaoMin(have, n, m);
			BigInteger mu = ONE;
			for (int i = 1; i <= n; i++)
				mu = mu.multiply(BigInteger.valueOf(i));
			for (int i = 1; i <= m; i++)
				mu = mu.divide(BigInteger.valueOf(i));
			for (int i = 1; i <= n - m; i++)
				mu = mu.divide(BigInteger.valueOf(i));
			BigInteger mah = mu.gcd(maAns);
			BigInteger mih = mu.gcd(miAns);
			System.out.println(maAns.divide(mah) + "/" + mu.divide(mah));
			System.out.println(miAns.divide(mih) + "/" + mu.divide(mih));
			System.out.println("");
		}

	}

}

Problem G: TwoPipelines

有两条直线,N个 点,要让N个点分别两这两条中的一条,求最短的距离和。要求连着两条直线的点的数量差不超过C

Solution

Tag:贪心,计算几何

求出所有点连第一条的距离与第二条线的距离的差值,排序。若现在取k个与第1条线相连,必然选排序后前k个点连。枚举k,记录合法的最优值即可。

 

/*
 * Author:  chlxyd
 * Created Time:  2013/7/29 13:25:43
 * File Name: G.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 = 400 + 10;

struct point {
    double x, y;
    point (double _x = 0, double _y = 0) : x(_x), y(_y) {
    }
    void input() {
        scanf("%lf%lf", &x, &y);
    }
    void output() {
        printf("%.3f%.3f\n", x, y);
    }
    double operator * (const point &p) const {
        return (x * p.y) - (y * p.x);
    }
    double operator ^ (const point &p) const {
        return (x * p.x) + (y * p.y);
    }
    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);
    }
    double len() {
        return sqrt(x * x + y * y);
    }
};

double getDis(point s, point e, point p) {
    return abs(((e - s) * (p - s)) / (e - s).len());
}

int n, m;
point lp1, lp2, lp3, lp4;
point po[maxn];
double dis[maxn], c1[maxn], c2[maxn], costx[maxn], costy[maxn];
int v[maxn], id[maxn];

bool cmp(const int &x, const int &y) {
    return dis[x] < dis[y];
}
int main(){
    while (scanf("%d%d", &n, &m) == 2) {
        lp1.input();
        lp2.input();
        lp3.input();
        lp4.input();
        rep (i, n) {
            int x;
            po[i].input();
            scanf("%d", &x);
            c1[i] = getDis(lp1, lp2, po[i]) * x;
            c2[i] = getDis(lp3, lp4, po[i]) * x;
            dis[i] = (c1[i] - c2[i]);
            id[i] = i;
            //printf("%.2f %.2f %.2f\n", c1[i], c2[i], dis[i]);
        } 
        
        double ans = 1e100; 
        int ansid;
        sort(id, id + n, cmp);
        repf (i, 0, n) {
            if (i != 0) {
                costx[i] = costx[i - 1];
                costx[i] += c1[id[i - 1]];
            }
            else costx[i] = 0;
        } 
        repd (i, n + 1, 0) {
            if (i != n + 1) {
                costy[i] = costy[i + 1];
                costy[i] += c2[id[i - 1]];
            }
            else costy[i] = 0;
        }
        repf (i, 0, n) {
            int j = n - i;
            if (abs(i - j) > m) continue;
            double co = costx[i] + costy[i + 1];
            //printf("=%.2f %.2f %.2f\n", co, costx[i], costy[i + 1]);
            if (ans == -1 || co < ans) {
                ans = co;
                ansid = i;
            }
        }
        //printf("%.2f %d\n", ans, ansid);
        memset(v, 0, sizeof(v));
        rep (i, ansid)
           v[id[i]] = 1;
        rep (i, n) {
            if (i != 0) printf(" ");
            if (v[i] == 1) printf("1");
            else printf("2");
        }
        printf("\n\n");
    }
    return 0;
}

Problem H: RegularWords

问有多少种长度为n的序列,其中a,b,c数量相同,且对于任意前缀,a的数量不小于b的数量不小于c的数量。

Solution

TagDP

Dp[i][j]表示长度为i序列,aj个,bk个,那么c自然有i-j-k个,枚举当前位选哪一个,可以递推到dp[i+1][j+1][k],dp[i+1][j][k+1]dp[i+1][j][k]

 

/*
 * Author:  chlxyd
 * Created Time:  2013/7/29 12:58:42
 * 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) ((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) )
#define maxn 62 
struct big {
    int a[100] ;
    int l ;
    void clear() {
        clr(a) ; l = 1 ;
    }
    big operator + ( const big &q) const {
        big now ;
        now.clear() ;
        now.l = max( l , q.l ) ;
        repf( i , 1 , now.l )
            now.a[i] = a[i] + q.a[i] ;
        repf( i , 1 , now.l + 2 ) {
            if ( now.a[i] >= 10 ) {
                now.a[i+1] += now.a[i] / 10 ;
                now.a[i] %= 10 ;
            }
        }
        if ( now.a[now.l+1] != 0 ) now.l ++ ;
        return now ;
    }
    void show() {
        while ( l > 1 && a[l] == 0 ) l -- ;
        repd( i , l , 1 ) 
            printf("%d" , a[i] ) ;
        puts("") ;
    }
    bool zero() {
        if ( l == 1 && a[1] == 0 ) return true ;
        return false ;
    }
};
big dp[2][maxn][maxn] ;
big ans[maxn] ;
int n ;
int main(){
    repf( i , 0 , 1 )
        repf( j , 0 , i )
            repf( k , 0 , min( j , i - j ) )
                dp[i][j][k].clear() ;
    int flag = 0 ;
    dp[1][1][0].a[1] = 1 ;
    repf( i , 1 , 180 ) {
        //cout<<i<<endl;
        flag = 1 - flag ;
        repf( j , 0 , 60 )
            repf( k , 0 , 60 )
                dp[1-flag][j][k].clear() ;
        repf( j , 0 , min(i,60) ) 
            repf( k , 0 , min( j , i - j ) ) {
                int l = i - j - k ;
                if ( l > k || l > j || k > j ) continue ;
                if ( !dp[flag][j][k].zero() ) {
                    dp[1-flag][j+1][k] = dp[1-flag][j+1][k] + dp[flag][j][k] ;
                    if ( j > k ) 
                        dp[1-flag][j][k+1] = dp[1-flag][j][k+1] + dp[flag][j][k] ;
                    if ( k > l ) 
                        dp[1-flag][j][k] = dp[1-flag][j][k] + dp[flag][j][k] ;
                }
            }
        if ( i % 3 == 0 ) ans[i/3] = dp[flag][i/3][i/3] ;
    }
    while ( scanf("%d" , &n ) == 1 ) {
        ans[n].show();
        cout<<endl;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值