A - Equal Sum Sets
题意:
输入三个数 n, k, s .
求有多少种集合元素个数为k,元素最大值为n,元素之和为s,集合中元素均不相同.
思路:
- 暴力
由于 n≤20 ,那么只有 220=106 种集合,那么枚举集合判断是否符合条件即可,复杂度为 O(2n∗k) ,但由于有100组样例。。所以只能很勉强地过,n 再大一点就得跪。
并不推荐这种做法。。 - DP
dp[i][j][k]表示 n = i , k = j , s = k 的集合数,dp[i][j][k]可以由两种状态转移得到,一种是集合中有元素 i 的,一种是没有的。
即 dp[i][j][k]=dp[i−1][j][k]+dp[i−1][j−1][k−i]
代码1(暴力):
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n , k , s ;
while ( cin >> n >> k >> s ) {
if ( !n && !k && !s ) break ;
int total = ( 1 << n ) ;
int ans = 0 ;
for ( int i = 0 ; i < total ; i++ ) {
int tmp = i , sum = 0 ;
int a = 1 , cnt = 0 ;
while ( tmp ) {
if ( tmp & 1 ) {
sum += a ;
cnt++ ;
if ( sum > s || cnt > k ) break ;
}
a++ ; tmp >>= 1 ;
}
if ( sum == s && cnt == k ) ans ++ ;
}
cout << ans << endl ;
}
return 0;
}
代码2(DP):
#include<bits/stdc++.h>
using namespace std;
int n , k , s ;
int dp[22][12][200] ;
void init()
{
dp[0][0][0] = 1 ;
for ( int i = 1 ; i <= 20 ; i++ )
for ( int j = 0 ; j <= 10 ; j++ )
for ( int k = 0 ; k <= 160 ; k++ )
{
dp[i][j][k] = dp[i-1][j][k] ;
if ( j && k >= i )
dp[i][j][k] += dp[i-1][j-1][k-i] ;
}
}
int main()
{
init() ;
while ( ~scanf( "%d%d%d" ,&n ,&k ,&s ) )
{
if ( !n && !k && !s ) break ;
printf( "%d\n" , dp[n][k][s] ) ;
}
return 0;
}
B - The Last Ant
题意:
输入两个数 n , l .
n 代表蚂蚁的数量,l 代表木板的长度,接下来输入 n 只蚂蚁所在的位置与行动的方向。
若两只蚂蚁在相邻的两格之间相遇,则掉头而行;若相遇位置在一格中心,则继续沿原方向前进。
已知蚂蚁速度为 1 格/s,求所有蚂蚁都掉下木板所需的时间,并求出最后一个离开木板的蚂蚁编号。
思路:
模拟,模拟,模拟。。
代码:
#include<bits/stdc++.h>
using namespace std;
struct Ant{
int id, pos, leave;
char dir[2] ;
bool operator < ( const Ant &a )const {
return pos < a.pos ;
}
};
Ant a[25] ;
int n , l ;
void turn( int i , int j ) {
if ( a[i].dir[0] == 'L' ) a[i].dir[0] = 'R' ;
else a[i].dir[0] = 'L' ;
if ( a[j].dir[0] == 'L' ) a[j].dir[0] = 'R' ;
else a[j].dir[0] = 'L' ;
}
void work()
{
int time = 0 ;
int out = 0 ;
Ant last[2] ;
while ( 1 ) {
time ++ ;
for ( int i = 0 ; i < n ; i++ ) {
if ( a[i].pos <= 0 || a[i].pos >= l ) continue ;
if ( a[i].dir[0] == 'R' ) a[i].pos++ ;
else a[i].pos-- ;
if ( a[i].pos == 0 || a[i].pos == l ) {
out++ ; a[i].leave = time ;
last[out&1] = a[i] ;
}
}
sort( a , a + n ) ;
for ( int i = 0 ; i < n - 1 ; i++ ) {
if ( a[i].pos == a[i+1].pos )
turn( i , i+1 ) ;
}
if ( out >= n ) break ;
}
int ans = last[out&1].id;
if ( last[1].leave == last[0].leave ) {
if ( last[0].dir[0] == 'L' )
ans = last[0].id ;
else
ans = last[1].id ;
}
cout << time << ' ' << ans << endl ;
}
int main()
{
//freopen("my.in","r",stdin);
//freopen("my.out","w",stdout);
while ( scanf( "%d%d" ,&n ,&l ) , n || l ) {
for ( int i = 0 ; i < n ; i++ ) {
scanf( "%s%d" ,a[i].dir ,&a[i].pos ) ;
a[i].id = i + 1 ;
}
sort( a , a + n ) ;
work() ;
}
return 0;
}
C - Count the Regions
题意:
给 n 个矩形的坐标,计算整个平面被矩形分成了几个区域。
思路:
先离散化,然后把所有矩形边标记为1,然后枚举每一个图内的点,若标记为0则dfs染色,遇到边界停止,并且将答案+1.
代码:
//2015/11/1 13:55:53
//#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<functional>
#include<string>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<stack>
#include<bitset>
#include<ctime>
using namespace std;
#define clr( x , y ) memset(x,y,sizeof(x))
#define cls( x ) memset(x,0,sizeof(x))
#define pr( x ) cout << #x << " = " << x << endl
#define pri( x ) cout << #x << " = " << x << " "
#define test( t ) int t ; cin >> t ; int kase = 1 ; while( t-- )
#define out( kase ) printf( "Case %d: " , kase++ )
#define sqr( x ) ( x * x )
#define mp make_pair
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
typedef long long lint;
const double eps = 1e-8 ;
const int inf = 0x3f3f3f3f ;
const long long INF = 0x3f3f3f3f3f3f3f3fLL ;
struct Rec{
int l , r , t , b ;
void input() {
scanf( "%d%d%d%d" ,&l ,&t ,&r ,&b ) ;
}
}rec[60] ;
const int L = 1e6 + 10 ;
int x[120],y[120] ;
int xx[L] , yy[L] ;
int G[240][240] ;
int n , ans , kx , ky , lenx , leny ;
const int dir[4][2] = { 1, 0, -1, 0, 0, 1, 0, -1 } ;
void discrete()
{
sort( x , x + kx ) ;
sort( y , y + ky ) ;
lenx = unique( x , x + kx ) - x ;
leny = unique( y , y + ky ) - y ;
for ( int i = 0 ; i < lenx ; i++ ) xx[x[i]] = 2 * i ;
for ( int i = 0 ; i < leny ; i++ ) yy[y[i]] = 2 * i ;
for ( int i = 0 ; i < n ; i++ ) {
int x1 = xx[rec[i].l] ;
int x2 = xx[rec[i].r] ;
int y1 = yy[rec[i].t] ;
int y2 = yy[rec[i].b] ;
for ( int j = x1 ; j <= x2 ; j++ ) G[j][y1] = G[j][y2] = 1 ;
for ( int j = y2 ; j <= y1 ; j++ ) G[x1][j] = G[x2][j] = 1 ;
}
}
bool check( int i , int j )
{
bool ok = ( i >= 1 && j >= 1 && i <= 2 * lenx - 2 && j <= 2 * leny - 2 ) ;
return ok ;
}
void dfs( int i , int j )
{
G[i][j] = 1 ;
for ( int k = 0 ; k < 4 ; k++ ) {
int tmpi = i + dir[k][0] ;
int tmpj = j + dir[k][1] ;
if ( check( tmpi , tmpj ) && !G[tmpi][tmpj] )
dfs( tmpi , tmpj ) ;
}
}
void find() {
ans = 0 ;
for ( int i = 0 ; i < ( lenx << 1 ) ; i++ ) {
if ( !G[i][0] ) dfs( i , 0 ) ;
int tmp = ( leny << 1 ) - 1 ;
if ( !G[i][tmp] ) dfs( i , tmp ) ;
}
for ( int i = 0 ; i < ( leny << 1 ) ; i++ ) {
if ( !G[0][i] ) dfs( 0 , i ) ;
int tmp = ( lenx << 1 ) - 1 ;
if ( !G[tmp][i] ) dfs( tmp , i ) ;
}
for ( int i = 0 ; i < ( lenx << 1 ) ; i++ ) {
for ( int j = 0 ; j < ( leny << 1 ) ; j++ ) {
if ( !G[i][j] ) ans++ , dfs( i , j ) ;
}
}
}
int main()
{
//freopen("my.in","r",stdin);
//freopen("my.out","w",stdout);
while ( cin >> n && n ) {
kx = 0 , ky = 0 ;
cls( G ) ;
for ( int i = 0 ; i < n ; i++ ) {
rec[i].input() ;
x[kx++] = rec[i].l ;
x[kx++] = rec[i].r ;
y[ky++] = rec[i].t ;
y[ky++] = rec[i].b ;
}
discrete() ;
find() ;
cout << ans + 1 << endl ;
}
return 0;
}
D - Clock Hands
题意:
有一个时钟,时针每 H 小时走一圈。
现在给你一个时刻,求该时刻之后最近的时刻 t ,在时刻 t ,秒针与分针的夹角等于秒针与时针的夹角。
时刻 t 的秒数用分数表示。
思路:
先吐槽一下,,时钟的题目一般都是在纸上写啊写,推出个公式,然后照着公式A过去就行了,结果这题用了半小时推公式,写代码用了两小时。。还是 too simple 啊。
设时钟一周的角度为 1,输入时刻为 h : m : s。
秒针转动角度:angs=s60分针转动角度:angm=m60+s3600时针转动角度:angh=hH+m60H+s3600H
设经过 t 秒后,秒针与分针的夹角等于秒针与时针的夹角,即
2∗angs′=angm′+angh′
还有一种情况是分针在0右边,时针在0左边,起初秒针在0
左边,过了几秒后秒针过0,此时,相当于秒针角度减少了一周,所以要在原公式里补上圈数k(k是整数):
设 angs′=angs+angtangm−angs′=angs′+1−angh2∗angs′+1=angm+angh即 2∗(angt+angs)+k=angm+angh
至于分数的处理可以用分数类来做,或者把上式代入来计算gcd:
(119H−1)(s+t)=60(H+1)m+3600h−3600Hk
代码:
#include<bits/stdc++.h>
using namespace std;
int gcd( int a , int b ) {
return b? gcd( b ,a % b ) : a ;
}
int main()
{
//freopen("my.in","r",stdin);
//freopen("my.out","w",stdout);
int H , h , m , s ;
while ( cin >> H >> h >> m >> s ) {
if ( !H && !m && !h && !s ) break ;
int tmp = 119*H - 1 ;
//(119H-1)(s+t) = 60(1+H)m + 3600h - 3600Hk
int t = 60*(1+H)*m + 3600*h - 3600*H - tmp*s ;
while ( t < 0 ) t += 3600*H ;
int sec = 60 * s * tmp + 60 * t ;
int min = 60 * m * tmp + sec / 60 ;
int hour ;
if ( sec == min ) t += 3600*H ;
sec = s * tmp + t ;
min = m + sec / ( tmp * 60 ) ;
hour = h + min / 60 ;
min %= 60 ; hour %= H ; sec %= tmp * 60 ;
int d = gcd( sec , tmp ) ;
printf( "%d %d %d %d\n" ,hour ,min ,sec/d ,tmp/d ) ;
}
return 0;
}
E - Dragon’s Cruller
思路:
题意略去。。
这题想通了其实挺简单的,康拓展开+优先队列+bfs。
把九宫格转换成一行,那么一个状态就是一种排列,用康拓展开将排列映射到一个数字,然后搜索状态直到符合所求状态,用优先队列维护花费。
代码:
/*
Creat Time:2015/11/2 21:27:15
*/
//#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<functional>
#include<string>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<stack>
#include<bitset>
#include<ctime>
#define clr( x , y ) memset(x,y,sizeof(x))
#define cls( x ) memset(x,0,sizeof(x))
#define pr( x ) cout << #x << " = " << x << endl
#define pri( x ) cout << #x << " = " << x << " "
#define test( t ) int t ; cin >> t ; int kase = 1 ; while( t-- )
#define out( kase ) printf( "Case %d: " , kase++ )
#define sqr( x ) ( x * x )
#define mp make_pair
#define pii pair<int,int>
#define fi fist
#define se second
#define pb push_back
using namespace std;
typedef long long lint;
const double eps = 1e-8 ;
const int inf = 0x3f3f3f3f ;
const long long INF = 0x3f3f3f3f3f3f3f3fLL ;
const int fac[10] = { 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880 } ;
const int N = 363000 ;
int ch , cv ;
int a[9] , b[9] , cost[N] ;
int fi , ed ;
bool vis[N] ;
struct Node{
int x , w ;
Node( int _x , int _w ):x(_x) , w(_w) {}
bool operator < ( const Node &a )const {
if ( w != a.w ) return w > a.w ;
return x < a.x ;
}
} ;
priority_queue<Node> q ;
int A2int( int *a , int n )
{
int res = 0 ;
for ( int i = 0 ; i < n ; i++ ) {
int tmp = a[i] ;
for ( int j = 0 ; j < i ; j++ ) {
if ( a[j] < a[i] ) tmp-- ;
}
res += fac[n-1-i] * tmp ;
}
return res ;
}
void int2A( int x , int *a , int n )
{
bool flag[10] ;
int j ;
cls( flag ) ;
for ( int i = 0 ; i < n ; i++ ) {
int tmp = x / fac[n-1-i] ;
for ( j = 0 ; j < n ; j++ ) {
if ( !flag[j] ) {
if ( !tmp ) break ;
tmp -- ;
}
}
a[i] = j , flag[j] = 1 ;
x %= fac[n-i-1] ;
}
}
void update( int num , int cos )
{
if ( !vis[num] && cos < cost[num] )
cost[num] = cos, q.push( Node( num , cos ) ) ;
}
void bfs()
{
while ( !q.empty() ) {
Node p = q.top() ; q.pop() ;
if ( vis[p.x] ) continue ;
vis[p.x] = true ;
if ( p.x == ed ) {
printf( "%d\n" , p.w ) ;
break ;
}
int2A( p.x , a , 9 ) ;
int k = 0 , tmp ;
while ( a[k] > 0 ) k++ ;
swap( a[k] , a[(k+1) % 9] ) ; //left
tmp = A2int( a , 9 ) ;
update( tmp , p.w + ch ) ;
swap( a[k] , a[(k+1) % 9] ) ;
swap( a[k] , a[(k+8) % 9] ) ; //right
tmp = A2int( a , 9 ) ;
update( tmp , p.w + ch ) ;
swap( a[k] , a[(k+8) % 9] ) ;
swap( a[k] , a[(k+3) % 9] ) ; //up
tmp = A2int( a , 9 ) ;
update( tmp , p.w + cv ) ;
swap( a[k] , a[(k+3) % 9] ) ;
swap( a[k] , a[(k+6) % 9] ) ; //down
tmp = A2int( a , 9 ) ;
update( tmp , p.w + cv ) ;
swap( a[k] , a[(k+6) % 9] ) ;
}
}
int main()
{
//freopen("my.in","r",stdin);
//freopen("my.out","w",stdout);
while ( ~scanf( "%d%d" ,&ch ,&cv ) ) {
if ( !ch && !cv ) break ;
for ( int i = 0 ; i < 9 ; i++ ) scanf( "%d" , a + i ) ;
for ( int i = 0 ; i < 9 ; i++ ) scanf( "%d" , b + i ) ;
fi = A2int( a , 9 ) ; ed = A2int( b , 9 ) ;
cost[fi] = 0 ;
while ( !q.empty() ) q.pop() ;
cls( vis ) , clr( cost , inf ) ;
q.push( Node( fi , 0 ) ) ;
bfs() ;
}
return 0;
}