A - Creating a Character
# include <iostream>
# include <cstdio>
using namespace std;
int t, a, b, c;
int main ( )
{
cin>> t;
while ( t-- )
{
int ans= 0 ;
scanf ( "%d%d%d" , & a, & b, & c) ;
int cha= a+ c- b;
if ( cha> 0 )
{
ans++ ;
int tmp= ( cha/ 2 - ( cha% 2 == 0 ) ) ;
ans+= min ( tmp, c) ;
}
cout<< ans<< endl;
}
return 0 ;
}
B - Zmei Gorynich
签到题 求最少几下把龙砍死,贪心,斩杀线以上用差值高的,最后一下用伤害高的。特判的答案没输出换行,白给两发WA。
# include <iostream>
# include <cstdio>
# include <algorithm>
using namespace std;
int t, n, x;
int main ( )
{
cin>> t;
while ( t-- )
{
int def= 0 , cha= 0 ;
scanf ( "%d%d" , & n, & x) ;
for ( int i= 1 , d, h; i<= n; i++ )
{
scanf ( "%d%d" , & d, & h) ;
def= max ( def, d) ;
cha= max ( cha, d- h) ;
}
if ( cha<= 0 && def< x)
{
cout<< - 1 << endl;
continue ;
}
if ( def>= x)
{
cout<< 1 << endl;
continue ;
}
int tmp= ( x- def) / cha+ ( ( x- def) % cha!= 0 ) ;
cout<< tmp+ 1 << endl;
}
return 0 ;
}
C - The Battle of Chibi
签到题 很容易想到朴素的dp,dp(i,j)表示当前在i选取了j个数的方案数,n^2的状态,每次n的转移,总时间复杂度O(n ^ 3),但是不难发现对于每个状态的转移实际上是一个离散化后的区间求和(甚至是个前缀和),所以数据结构维护一下就好了。 树状数组可,这题卡常,不能用map,其实可以进一步降低常数,把对离散化的位置查询降为O(1)。线段树常数大些,不知道行不行。 状态的定义有时为了方便还是需要认为的增加含义。
# include <iostream>
# include <cstdio>
# include <algorithm>
# include <map>
# include <cstring>
using namespace std;
const int mod = 1000000007 ;
int t, n, m, f[ 1005 ] [ 1005 ] , a[ 1005 ] , tree[ 1005 ] , b[ 1005 ] , num;
int lowbit ( int x)
{
return x& - x;
}
void addss ( int x, int k)
{
while ( x<= n)
{
tree[ x] = ( tree[ x] + k) % mod;
x+= lowbit ( x) ;
}
}
int query ( int x)
{
int ans= 0 ;
while ( x> 0 )
{
ans= ( ans+ tree[ x] ) % mod;
x-= lowbit ( x) ;
}
return ans;
}
int main ( )
{
cin>> t;
while ( t-- )
{
num++ ;
int cnt= 0 ;
scanf ( "%d%d" , & n, & m) ;
for ( int i= 1 ; i<= n; i++ )
{
scanf ( "%d" , & a[ i] ) ;
b[ i] = a[ i] ;
f[ i] [ 1 ] = 1 ;
}
sort ( b+ 1 , b+ 1 + n) ;
cnt= unique ( b+ 1 , b+ n+ 1 ) - b- 1 ;
for ( int i= 2 ; i<= m; i++ )
{
memset ( tree, 0 , sizeof ( tree) ) ;
for ( int j= 1 ; j<= i- 1 ; j++ )
{
if ( f[ j] [ i- 1 ] )
{
int pos= lower_bound ( b+ 1 , b+ 1 + cnt, a[ j] ) - b;
addss ( pos, f[ j] [ i- 1 ] ) ;
}
}
for ( int j= i; j<= n; j++ )
{
int pos= lower_bound ( b+ 1 , b+ 1 + cnt, a[ j] ) - b;
f[ j] [ i] = query ( pos- 1 ) % mod;
if ( f[ j] [ i- 1 ] )
addss ( pos, f[ j] [ i- 1 ] ) ;
}
}
int ans= 0 ;
for ( int i= 1 ; i<= n; i++ )
ans= ( ans% mod+ f[ i] [ m] % mod) % mod;
printf ( "Case #%d: %d\n" , num, ans) ;
for ( int i= 1 ; i<= n; i++ )
for ( int j= 1 ; j<= m; j++ )
f[ i] [ j] = 0 ;
}
return 0 ;
}
D - Hanoi tower
汉诺塔问题中求当三个竹子套的一样多时所需步数。 打表找规律,我也瞪不出啥规律,这方面一直不行,c++写需要高精。python好像可以写的又短又好看。 下学期要学好python
a = [ 0 ] * 105 ;
a[ 1 ] = 2
a[ 2 ] = 9
deta = 97
for i in range ( 3 , 103 ) :
if i% 2 == 1 :
a[ i] = a[ i- 1 ] * 4 + 2
else :
a[ i] = a[ i- 1 ] + deta
deta = 15 * deta + deta- 15
# print ( a)
# n = int ( int ( input ( ) ) / 3 )
In = open ( "input.txt" , "r" )
Out = open ( "output.txt" , "w" )
n = int ( int ( In. read ( ) ) / 3 )
Out. write ( str ( a[ n] ) )
# print ( a[ n] )
E - Invoker
签到题 其实是个难度较低的线性dp,但是题意太容易搞错了。 DOTA2中要打出技能需要三个元素然后需要一个R,手头上只能保留三个元素(R不算),求按顺序打出给定技能所需要添加的最少元素数,当有三个元素时再添加元素将删除最开始添加的那个元素。 当前持有的元素只有添加顺序的先后,但是打技能的时候可以随意(每个元素只算一次),比如当前为EWE,是可以打出WEE的。 dp(i,j),要打第i个技能时所持元素有六种情况(3的排列),dp(i,j)=min(dp(i-1,k)+此情况需添加元素数),1<=j<=6,1<=k<=6。
# include <iostream>
# include <cstdio>
# include <cstring>
using namespace std;
char s[ 100005 ] , nw[ 5 ] ;
int dp[ 100005 ] [ 10 ] ;
string ss[ 105 ] ;
int gt ( char a)
{
return a- 'A' ;
}
int solve ( int a, int b)
{
int ans= 1e9 ;
char nw[ 5 ] , nww[ 5 ] ;
if ( b== 1 || b== 2 )
nw[ 0 ] = ss[ gt ( s[ a] ) ] [ 0 ] ;
if ( b== 3 || b== 4 )
nw[ 0 ] = ss[ gt ( s[ a] ) ] [ 1 ] ;
if ( b== 5 || b== 6 )
nw[ 0 ] = ss[ gt ( s[ a] ) ] [ 2 ] ;
if ( b== 3 || b== 5 )
nw[ 1 ] = ss[ gt ( s[ a] ) ] [ 0 ] ;
if ( b== 1 || b== 6 )
nw[ 1 ] = ss[ gt ( s[ a] ) ] [ 1 ] ;
if ( b== 2 || b== 4 )
nw[ 1 ] = ss[ gt ( s[ a] ) ] [ 2 ] ;
int tot= ss[ gt ( s[ a] ) ] [ 0 ] + ss[ gt ( s[ a] ) ] [ 1 ] + ss[ gt ( s[ a] ) ] [ 2 ] ;
nw[ 2 ] = tot- nw[ 0 ] - nw[ 1 ] ;
for ( int i= 1 ; i<= 6 ; i++ )
{
if ( i== 1 || i== 2 )
nww[ 0 ] = ss[ gt ( s[ a- 1 ] ) ] [ 0 ] ;
if ( i== 3 || i== 4 )
nww[ 0 ] = ss[ gt ( s[ a- 1 ] ) ] [ 1 ] ;
if ( i== 5 || i== 6 )
nww[ 0 ] = ss[ gt ( s[ a- 1 ] ) ] [ 2 ] ;
if ( i== 3 || i== 5 )
nww[ 1 ] = ss[ gt ( s[ a- 1 ] ) ] [ 0 ] ;
if ( i== 1 || i== 6 )
nww[ 1 ] = ss[ gt ( s[ a- 1 ] ) ] [ 1 ] ;
if ( i== 2 || i== 4 )
nww[ 1 ] = ss[ gt ( s[ a- 1 ] ) ] [ 2 ] ;
tot= ss[ gt ( s[ a- 1 ] ) ] [ 0 ] + ss[ gt ( s[ a- 1 ] ) ] [ 1 ] + ss[ gt ( s[ a- 1 ] ) ] [ 2 ] ;
nww[ 2 ] = tot- nww[ 0 ] - nww[ 1 ] ;
if ( nw[ 0 ] == nww[ 0 ] && nw[ 1 ] == nww[ 1 ] && nw[ 2 ] == nww[ 2 ] )
ans= min ( ans, dp[ a- 1 ] [ i] + 1 ) ;
else
if ( nww[ 1 ] == nw[ 0 ] && nww[ 2 ] == nw[ 1 ] )
ans= min ( ans, dp[ a- 1 ] [ i] + 2 ) ;
else
if ( nww[ 2 ] == nw[ 0 ] )
ans= min ( ans, dp[ a- 1 ] [ i] + 3 ) ;
else
ans= min ( ans, dp[ a- 1 ] [ i] + 4 ) ;
}
return ans;
}
int main ( )
{
ss[ 'Y' - 'A' ] = "QQQ" ;
ss[ 'V' - 'A' ] = "QQW" ;
ss[ 'G' - 'A' ] = "QQE" ;
ss[ 'C' - 'A' ] = "WWW" ;
ss[ 'X' - 'A' ] = "QWW" ;
ss[ 'Z' - 'A' ] = "WWE" ;
ss[ 'T' - 'A' ] = "EEE" ;
ss[ 'F' - 'A' ] = "QEE" ;
ss[ 'D' - 'A' ] = "WEE" ;
ss[ 'B' - 'A' ] = "QWE" ;
scanf ( "%s" , s) ;
int len= strlen ( s) ;
for ( int i= 1 ; i<= 6 ; i++ )
dp[ 0 ] [ i] = 4 ;
for ( int i= 1 ; i< len; i++ )
{
for ( int j= 1 ; j<= 6 ; j++ )
{
dp[ i] [ j] = solve ( i, j) ;
}
}
int minn= 1e9 ;
for ( int i= 1 ; i<= 6 ; i++ )
minn= min ( minn, dp[ len- 1 ] [ i] ) ;
cout<< minn;
return 0 ;
}