牛客基础题全面提升 1
NC16644 字符串的展开
按照题目进行模拟,要考虑几种特殊情况,开头或结尾是-
,或者中间有连续多个-
#include<bits/stdc++.h>
using namespace std;
int p1 , p2 , p3;
string s;
void opt( char start , char end ){
if( start + 1 == end ) return;
if( start == '-' || end == '-' || (end <= start) || ( start>='a' && start<='z' && end>='0' && start<='9' ) || ( start>='0' && start<='9' && end>='a' && start<='z' ) ){
cout << "-";
return;
}
if( p3 == 1 ){
if( start >= 'a' && start <= 'z' && p1 == 2 )
for( char it = start + 'A'-'a' + 1 ; it < end + 'A'-'a' ; it ++ )
for( int j = 1 ; j <= p2 ; j ++ )
cout << it;
else
for( char it = start+1 ; it < end ; it ++ )
for( int j = 1 ; j <= p2 ; j ++ )
cout << ( p1 == 3 ? '*' : it );
}
else {
if( start >= 'a' && start <= 'z' && p1 == 2 )
for( char it = end + 'A'-'a' - 1 ; it > start + 'A'-'a' ; it -- )
for( int j = 1 ; j <= p2 ; j ++ )
cout << it;
else
for( char it = end-1 ; it > start ; it -- )
for( int j = 1 ; j <= p2 ; j ++ )
cout << ( p1 == 3 ? '*' : it );
}
}
int main()
{
cin >> p1 >> p2 >> p3 >> s;
int i;
for( i = 0 ; i < s.size() ; i ++ )
{
if( s[i] != '-' ) break;
cout<<"-";
}
for( ; i < s.size() ; i ++ )
{
if( s[i] == '-' ) opt( s[i-1] , s[i+1] );
else cout << s[i];
}
}
NC16622 多项式输出
特判指数为n 、1、0 三种情况
其次注意系数大于零要输出加好
#include<bits/stdc++.h>
using namespace std;
int read(){
int x = 0 , f = 1 , ch = getchar();
while( (ch<'0'||ch>'9') && ch != '-' ) ch = getchar();
if( ch == '-' ) f = -1 , ch = getchar();
while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1) + ch-'0' , ch = getchar();
return x*f;
}
int main()
{
int n = read();
for( int i = n , a ; i > 0 ; i -- )
{
a = read();
if( a == 0 ) continue;
if( n != i && a > 0 ) cout << "+";
if( a == -1 ) cout << '-';
if( abs(a) != 1 ) cout << a;
if( i != 1 )cout << "x^"<<i;
else cout << "x";
}
n = read();
if( n > 0 ) cout << "+" << n;
else if( n != 0 ) cout << n;
}
NC16593 铺地毯
注意一点的是输入的数据是左下角和长宽。
倒序枚举一下就好了。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 10005;
int n , a[N][5];
int read(){
int x = 0 , f = 1 , ch = getchar();
while( ( ch < '0' || ch > '9' ) && ch != '-' ) ch = getchar();
if( ch == '-' ) f = -1 , ch = getchar();
while( ch >= '0' && ch <= '9' ) x = ( x << 3 ) + ( x << 1 ) + ch - '0' , ch = getchar();
return x * f;
}
int32_t main()
{
n = read();
for( int i = 1 ; i <= n ; i ++ )
for( int j = 1 ; j <= 4 ; j ++ ) a[i][j] = j > 2 ? a[i][j-2] + read() : read();
int x = read() , y = read();
for( int i = n ; i >= 1 ; i -- )
if( a[i][1] <= x && a[i][2] <= y && a[i][3] >= x && a[i][4] >= y )
printf("%lld\n" , i ) , exit(0);
cout << "-1\n";
}
NC16438 回文日期
回文日期一年最多只有一天,先枚举出年份构造出回文日期判断日期是否合法就好
#include <bits/stdc++.h>
using namespace std;
int sy , sm , sd , ey , em , ed , ss , ee;
int pending( int y , int m , int d )
{
if( m > 12 || m < 1) return 0;
switch (m) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
if( d > 31 ) return 0;
else return 1;
case 2: {
if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0) {
if (d > 29) return 0;
else return 1;
} else {
if (d > 28) return 0;
else return 1;
}
}
default: {
if (d > 30) return 0;
else return 1;
}
}
}
int main()
{
scanf("%4d%2d%2d" , &sy , &sm , &sd );
scanf("%4d%2d%2d" , &ey , &em , &ed );
if( sy == ey && sm == em && sd == ed )
{
int k = sd%10;
k = k * 10 + sd / 10 , k = k * 10 + sm % 10 , k = k * 10 + sm / 10;
cout << (sy == k) << endl;
}
else {
int ans = 0 , tm , td ;
ss = sy * 10000 + sm * 100 + sd , ee = ey * 10000 + em * 100 + ed;
for( int i = sy ; i <= ey ; i ++ )
{
tm = i%10*10 + i/10%10 , td = i/100%10*10+i/1000;
ans += pending( i , tm , td );
}
cout << ans << endl;
}
return 0;
}
NC24636 值周
虽然可以 用查分来写,但是我发现可以进行区间合并,用总长度减去合并后的区间长度就好了
#include <bits/stdc++.h>
#define int long long
using namespace std;
int read() {
int x = 0, f = 1, ch = getchar();
while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
if (ch == '-') f = -1, ch = getchar();
while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x * f;
}
int32_t main() {
int n = read() + 1, m = read();
vector<pair<int, int> > v;
for (int l, r; m; m--)
l = read(), r = read(), v.push_back({l, 0}), v.push_back({r, 1});
sort( v.begin() , v.end() );
int cnt = 0 , sta;
for( auto [ x , t ] : v ){
if( t == 0 ){
if( cnt == 0 ) sta = x;
cnt ++;
}
else{
cnt --;
if( cnt == 0 )
n -= x - sta + 1;
}
}
cout << n << endl;
}
NC235254 晾衣服
二分答案,判断一下,计算一下每一件衣服在规定时间晾干需要使用烘干机的次数
#include<bits/stdc++.h>
#define int long long
using namespace std;
int read() {
int x = 0, f = 1, ch = getchar();
while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
if (ch == '-') f = -1, ch = getchar();
while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x * f;
}
const int N = 1e5+5;
int n , a[N] ,k;
bool pending( int x ){
int cnt = 0;
for( int i = n ; a[i] > x ; i -- )
{
cnt += ( a[i] - x ) / ( k - 1 ) + ( ( a[i] - x ) % ( k - 1 ) > 0 );
if( cnt > x ) return 0;
}
return 1;
}
int32_t main() {
n = read();
for( int i = 1 ; i <= n ; i ++ ) a[i] = read();
sort( a + 1 , a + 1 + n );
k = read();
if( k == 1 ) printf("%lld\n" , a[n] ) , exit(0);
int l = 1 , r = 1e9 , mid , ans;
while( l <= r ){
mid = ( l + r ) >> 1;
if( pending(mid) ) ans = mid , r = mid - 1;
else l = mid + 1;
}
cout << ans << endl;
return 0;
}
NC 14893 栈和排序
这道题要先预处理里出i...n
中最大的数,在每次入栈前判断栈顶的数是否比i...n
的最大值大,如果是就出栈重复操作之道不满足,然后在入栈。所有数入栈后清空栈就好了
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+5;
int n , m , a[N] , b[N];
stack<int> stk;
int read() {
int x = 0, f = 1, ch = getchar();
while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
if (ch == '-') f = -1, ch = getchar();
while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x * f;
}
int32_t main() {
n = read();
for( int i = 1 ; i <= n ; i ++ )
a[i] = read();
for( int i = n ; i >= 1 ; i -- )
b[i] = max( a[i] , b[i+1] );
for( int i = 1 ; i <= n ; i ++ ){
while( stk.size() && stk.top() > b[i] )
{
cout << stk.top() << " ";
stk.pop();
}
stk.push( a[i] );
}
while( stk.size() )
{
cout << stk.top() << " ";
stk.pop();
}
return 0;
}
NC18386 字符串
这道题几乎就是双指针的模板题了。
每次移动一下左端点,然后移动右端点知道满足条件
#include<bits/stdc++.h>
using namespace std;
int v[300] = {};
int32_t main() {
string s;
cin >> s;
int l = 0 , r = -1 , len = s.size() , ans = 1e9 , k = 0;
while( l < len ){
while( r < len - 1 && k < 26 ) { // 右指针右移
r++, v[s[r]]++;
if (v[s[r]] == 1) k++;
}
if( k == 26 ) ans = min( ans , r - l + 1 ); // 满足条件
if( v[s[l]] == 1 ) k --; // 左指针右移
v[s[l]] -- , l ++;
}
cout << ans << endl;
return 0;
}
NC207040 丢手绢
这道题也可以用双指针来做。但是值得注意的是因为圆的性质,所以圆上两点之间的距离一定是小于等于半径的。所以如果右指针移动后距离大于半径了,右指针的移动就可以结束了。
#include<bits/stdc++.h>
using namespace std;
int read() {
int x = 0, f = 1, ch = getchar();
while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
if (ch == '-') f = -1, ch = getchar();
while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x * f;
}
const int N = 1e5+5;
int n , a[N] , ans , sum , cnt ;
int32_t main() {
n = read();
for( int i = 0 ; i < n ; i ++ )
a[i] = read() , sum += a[i];
for( int i = 0 , j = -1 ; i < n ; i ++ )
{
while( cnt * 2 < sum ){
j = ( j +1 ) % n , cnt += a[j];
ans = max( ans , min( cnt , sum - cnt ) );
}
cnt -= a[i];
}
cout << ans << endl;
return 0;
}
NC15173 The Biggest Water Problem
递归的操作就好了
#include<bits/stdc++.h>
using namespace std;
void dfs( int x ){
if( x < 10 ){
cout << x;
exit(0);
}
int y = 0;
while( x ) y += x % 10 , x /= 10;
dfs(y);
return;
}
int32_t main() {
int x;
cin >> x;
dfs(x);
return 0;
}
NC16644 字符串的展开
模拟题
#include<bits/stdc++.h>
using namespace std;
int p1 , p2 , p3;
string s;
void opt( char start , char end ){
if( start + 1 == end ) return;
if( start == '-' || end == '-' || (end <= start) || ( start>='a' && start<='z' && end>='0' && start<='9' ) || ( start>='0' && start<='9' && end>='a' && start<='z' ) ){
cout << "-";
return;
}
if( p3 == 1 ){
if( start >= 'a' && start <= 'z' && p1 == 2 )
for( char it = start + 'A'-'a' + 1 ; it < end + 'A'-'a' ; it ++ )
for( int j = 1 ; j <= p2 ; j ++ )
cout << it;
else
for( char it = start+1 ; it < end ; it ++ )
for( int j = 1 ; j <= p2 ; j ++ )
cout << ( p1 == 3 ? '*' : it );
}
else {
if( start >= 'a' && start <= 'z' && p1 == 2 )
for( char it = end + 'A'-'a' - 1 ; it > start + 'A'-'a' ; it -- )
for( int j = 1 ; j <= p2 ; j ++ )
cout << it;
else
for( char it = end-1 ; it > start ; it -- )
for( int j = 1 ; j <= p2 ; j ++ )
cout << ( p1 == 3 ? '*' : it );
}
}
int main()
{
cin >> p1 >> p2 >> p3 >> s;
int i;
for( i = 0 ; i < s.size() ; i ++ )
{
if( s[i] != '-' ) break;
cout<<"-";
}
for( ; i < s.size() ; i ++ )
{
if( s[i] == '-' ) opt( s[i-1] , s[i+1] );
else cout << s[i];
}
}
NC24739 Lake Counting
从每一个是湖且没有被访问过的点开始进行dfs
,统计dfs
的次数就是答案
#include <bits/stdc++.h>
using namespace std;
const int N = 105 , dx[] = { 0 , 0 , 1 , 1 , 1 , -1 , -1 , -1 } , dy[] = { 1 , -1 , 1 , -1 , 0 , 1 , 0 , -1 };
int n , m , v[N][N] , cnt;
void dfs( int x , int y )
{
if( x < 1 || y < 1 || x > n || y > m ) return ;
if( v[x][y] ) return;
v[x][y] = 1;
for( int i = 0 ; i < 8 ; i ++ ) dfs( x + dx[i] , y + dy[i] );
return;
}
int main()
{
cin >> n >> m;
for( int i = 1 ; i <= n ; i ++ )
{
for( int j = 1 , x ; j <= m ; j ++ )
{
do{
x = getchar();
}while( x != '.' && x != 'W' );
if( x == '.' ) v[i][j] = 1;
}
}
for( int i = 1 ; i <= n ; i ++ )
{
for( int j = 1 ; j <= m ; j ++ )
{
if( v[i][j] ) continue;
cnt ++;
dfs( i , j );
}
}
cout << cnt << endl;
return 0;
}
NC16710 最大公约数
模板
#include <bits/stdc++.h>
using namespace std;
int main(){
long long a , b;
cin >> a >> b;
cout << a / __gcd( a , b ) * b << endl;
}
NC16649 校门外的树
可以用区间合并来做,但是这里只要用差分来维护一下那些书被移走了就好
#include<bits/stdc++.h>
using namespace std;
const int N = 10005;
int L , m , res;
int a[N];
int main(){
cin >> L >> m;
for( int i = 1 , l , r ; i <= m ; i ++ ) {
cin >> l >> r ;
a[l] ++ , a[r+1] --;
}
for( int i = 1 ; i <= L ; i ++ )
a[i] += a[i-1];
for( int i = 0 ; i <= L ; i ++ )
res += ( a[i] == 0 );
cout << res << endl;
return 0;
}
NC21874 好串
一道看似复杂的题,把a
当做(
,把b
当做)
那么这就是一道括号匹配的问题
因为种类单一甚至不需要用到栈就可以解决
#include<bits/stdc++.h>
using namespace std;
int main(){
string s;
int tp = 0;
cin >> s;
for( auto it : s ){
if( it == 'a' ) tp ++;
else{
if( tp == 0 ){
cout << "Bad\n";
return 0;
}
tp --;
}
}
if( tp ){
cout << "Bad\n";
return 0;
}
cout << "Good\n";
return 0;
}
NC223888 红色和紫色
两个人都安装棋盘格的形式来涂颜色,所以就是问谁是最后一个下手的,这样的话判断格子总数的奇偶就好了
#include<bits/stdc++.h>
using namespace std;
int main(){
int n , m;
cin >> n >> m;
if( n & 1 && m & 1 )
cout << "akai\n";
else
cout << "yukari\n";
return 0;
}
NC208813 求逆序对数
暴力解法就是直接循环就好了
#include<bits/stdc++.h>
using namespace std;
const int N = 2005;
int n , a[N] , res;
int32_t main() {
cin >> n;
for( int i = 1 ; i <= n ; i ++ )
cin >> a[i];
for( int i = 1 ; i <= n ; i ++ )
for( int j = 1 ; j < i ; j ++ )
if( a[j] > a[i] ) res ++;
cout << res << endl;
return 0;
}
但是可以用树状数组来求一下,但是需要 hash 一下才可以
NC23050 华华对月月的忠诚
gcd(f[n],f[n+1]) = gcd( f[n+1]-f[n] , f[n] ) = gcd( f[n-1] , f[n] )
不断递推就可以得到
gcd(f[n],f[n+1]) = gcd( f[2] , f[1] )
#include<bits/stdc++.h>
using namespace std;
int32_t main() {
long long a , b;
cin >> a >> b;
cout << __gcd( a , b );
return 0;
}
NC235813 N皇后问题
通过dfs的方式进行枚举,枚举每一行的皇后位于那一列,可以通过一个数组来记录下哪一列有皇后,皇后在一条对角线上的情况就是两个皇后连线的斜率是正负1
#include<bits/stdc++.h>
using namespace std;
const int N = 15;
int n , row[N] , res;
bool colum[N];
void dfs( int x ){
if( x > n ){
res ++;
return ;
}
for( int i = 1 , f = 1 ; i <= n ; i ++ , f = 1 ){
if(colum[i] ) continue;
for( int j = 1 ; j < x && f ; j ++ ) // 判断对角线
if( abs( row[j] - i ) == abs( j - x ) ) f = 0;
if( !f ) continue;
colum[i] = 1 , row[x] = i;
dfs( x + 1 );
colum[i] = 0;
}
}
int main(){
cin >> n;
dfs( 1 );
cout << res << "\n";
}
NC18979 毒瘤xor
因为是异或操作,所以可以转化成对二进制考虑,统计一下每一位是0
多还是1
多,0
多这一位就是1
,防止就是0
,相同的因为输出较少的所以也是0
统计个数可以用前缀和处理
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5+5 , M = 35;
int n , pre[N][M];
int read() {
int x = 0, f = 1, ch = getchar();
while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
if (ch == '-') f = -1, ch = getchar();
while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x * f;
}
void f( int val , int t ){
for( int i = 0 ; val ; i ++)
pre[t][i] = val & 1 , val /= 2;
}
int32_t main() {
n = read();
for( int x , i = 1 ; i <= n ; i ++ )
x = read() , f( x , i );
for( int t = 0 ; t <= 31 ; t ++ )
for( int i = 1 ; i <= n ; i ++ ) pre[i][t] += pre[i-1][t];
for( int m = read() , l , r , len , res ; m ; m -- ){
l = read() , r = read() , len = r - l + 1 , res = 0;
for( int i = 0 ; i <= 30 ; i ++ )
if( (pre[r][i] - pre[l-1][i]) * 2 < len ) res += (1<<i);
printf("%lld\n" , res );
}
return 0;
}