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
Tag:DP
Dp[i][j]表示长度为i序列,a有j个,b有k个,那么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;
}
}