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; } }