蓝桥杯B组C++历届真题代码整理

2013年省赛真题

高斯日记

注意4月30号是第一天,可以先通过给出的例子5343天来验证。

#include <iostream>
using namespace std;
void datesearch(int number, int nowyear, int nowmonth, int Month[])
{
  number -= 1;
  int ansyear = 1777, ansmonth = 4, ansday = 30;
  for(int year = nowyear;; year++)
  {
    //cout << " year = " << year << " number = " << number << endl;
    if(number == 0) break;
    if((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) Month[1] = 29;
    else Month[1] = 28;
    if(year != nowyear) nowmonth = 0;
    for(int month = nowmonth; month < 12; month++)
    {
      if(Month[month] >= number)
      {
        ansyear = year;
        ansmonth = month+1;
        ansday = number;
        number = 0;
        break;
      }
      else
        number -= Month[month];
    }
  }
  cout << ansyear << "-" << ansmonth << "-" << ansday << endl;
}
int main()
{
    //freopen("d:in.txt","r",stdin);
    //freopen("d:testout.txt","w",stdout);
    int month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    int number = 8113;
    datesearch(number, 1777, 4, month);

    return 0;
}

马虎的算式

直接枚举所有的值就行.

#include <iostream>
using namespace std;

int main()
{
    //freopen("d:in.txt","r",stdin);
    //freopen("d:testout.txt","w",stdout);
    int sum = 0;
    for(int g = 1; g <= 9; g++) //g
    {
      for(int h = 1; h <= 9; h++) // h
      {
        if(h == g) continue;
        for(int j = 1; j <= 9; j++)  //j
        {
          if(j == g || j == h) continue;
          for(int k = 1; k <= 9; k++) // k
          {
            if(k == g || k == h || k == j) continue;
            for(int l = 1; l <= 9; l++) //l
            {
              if(l == g || l == h || l == j || l == k) continue;
              int ab = g*10 + h;
              int cde = j*100 + k*10 + l;
              int adb = g*100 + k*10 + h;
              int ce = j*10 + l;
              if(ab * cde == adb * ce) sum ++;
            }
          }
        }

      }
    }
    cout << sum << endl;
    return 0;
}

第39级台阶

注意刚开始处于第0级台阶而不是第1级。

解法1, 用bfs来做。

#include <iostream>
#include <queue>
using namespace std;

struct node
{
  int footstep; // 脚的步数,用来判断奇偶性
  int step; // 已经走了的台阶数
  node(int ft,int s): footstep(ft), step(s){}
};
void bfs()
{
  queue<node> Q;
  Q.push(node(0, 0));
  int sum = 0;
  while(!Q.empty())
  {
    node N = Q.front();
    Q.pop();
    if(N.footstep % 2 == 0 && N.step == 39) sum++;
    else
    {
      if(N.step + 1 <= 39) Q.push(node(N.footstep+1, N.step+1));
      if(N.step + 2 <= 39) Q.push(node(N.footstep+1, N.step+2));
    }
  }
  cout << sum << endl;
}
int main()
{
    //freopen("d:in.txt","r",stdin);
    //freopen("d:testout.txt","w",stdout);
    bfs();
    return 0;
}

解法2,用dfs来做。利用递推式 f(n) = f(n-1) + f(n-2). 第N级台阶数一定是第N-1和N-2级台阶数的和,然后从第39级台阶开始递归。

#include <iostream>
#include <queue>
using namespace std;

int ans = 0;
void dfs(int n, int step)
{
  if(n < 0) return ;
  if(n == 0 && step % 2 == 0)
  {
    ans++;
    return ;
  }

  dfs(n-1, step+1);
  dfs(n-2, step+1);
}
int main()
{
    //freopen("d:in.txt","r",stdin);
    //freopen("d:testout.txt","w",stdout);
    dfs(39, 0);
    cout << ans << endl;
    return 0;
}

黄金连分数

这道题作为填空题来说是非常麻烦的。
首先找出这个分数的规律,从分数的分子分母来判断出是个斐波那契数列。然后精确到小数点后一百位的除法计算又是大数的计算。所以要实现斐波那契的大数加法和大数除法。最后还要精确到小数点后101位,因为第101要四舍五入。精确的小数点后100位需要多次的输出来比较,等到100位都不会变化时就是稳定的时候。

#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;
const int maxn = 10;
string add(string a, string b)
{
  a = a.substr(a.find_first_not_of('0'));
  b = b.substr(b.find_first_not_of('0'));
  long long lenA = a.length();
  long long lenB = b.length();
  long long len = max(lenA,lenB) + maxn;
  int tmp = 0;
  string ans(len, '0');
  reverse(a.begin(), a.end());
  reverse(b.begin(), b.end());

  for(int i = 0; i < lenA; i++) ans[i] = a[i];
  for(int i = 0; i < len; i++)
  {
    if(i < lenB)
      tmp += (ans[i] - '0') + (b[i] - '0');
    else
      tmp += (ans[i] - '0');

      ans[i] = tmp % 10 + '0';
      tmp /= 10;
  }
  reverse(ans.begin(), ans.end());

  return ans.substr(ans.find_first_not_of('0'));
}
string sub(string a, string b) // 保证 a 一定大于 b
{
  a = a.substr(a.find_first_not_of('0'));
  b = b.substr(b.find_first_not_of('0'));
  long long lenA = a.length();
  long long lenB = b.length();
  long long len = max(lenA,lenB) + maxn;
  int tmp = 0;
  string ans(len, '0');
  reverse(a.begin(), a.end());
  reverse(b.begin(), b.end());

  for(int i = 0; i < lenA; i++) ans[i] = a[i];
  for(int i = 0; i < len; i++)
  {
    if(i < lenB)
      tmp += (ans[i] - '0') - (b[i] - '0');
    else
      tmp += (ans[i] - '0');
    if(tmp < 0)
    {
      ans[i] = (tmp + 10) % 10 + '0';
      tmp = -1;
    }
    else
    {
      ans[i] = tmp % 10 + '0';
      tmp = 0;
    }
  }
  reverse(ans.begin(), ans.end());

  return ans.substr(ans.find_first_not_of('0'));
}
int compare(string a, string b) // a > b return 1 a < b return -1
{
  if(a.length() > b.length()) return 1;
  else if(a.length() < b.length()) return -1;
  else
  {
    if(a == b) return 0;
    else if(a > b) return 1;
    else return -1;
  }
}
void divide(string a, string b, int num)
{
  int tmp = 0;
  while(compare(a, b) >= 1)
  {
    a = sub(a, b);
    tmp++;
  }
  cout << tmp << ".";
  while(num)
  {
    num--;
    tmp = 0;
    a.append("0");
    while(compare(a, b) >= 1)
    {
      a = sub(a, b);
      tmp++;
    }
    cout << tmp;
  }
}
int main()
{
    //freopen("d:in.txt","r",stdin);
    //freopen("d:testout.txt","w",stdout);
    string son = "1", mother = "1";
    for(int i = 1; i <= 505; i++)
    {
      string tmp = mother;
      mother = add(son, mother);
      son = tmp;
    }
    divide(son, mother, 101);

    return 0;
}

前缀判断

C语言的基础题。

#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;
const int maxn = 10;

char* prefix(char* haystack_start, char* needle_start)
{
    char* haystack = haystack_start;
    char* needle = needle_start;


    while(*haystack && *needle){
        if(*(haystack++) != *(needle++)) return NULL;  //填空位置
    }

    if(*needle) return NULL;

    return haystack_start;
}
int main()
{
    //freopen("d:in.txt","r",stdin);
    //freopen("d:testout.txt","w",stdout);
    char* haystack_start = "abc123";
    char* needle_start = "abc";
    cout << prefix(haystack_start, needle_start);
    return 0;
}

三部排序

如果x[p] > 0, 那么直接交换到右边界,右边界确定了所以right- -,如果 x[p] < 0,就和左边界交换,左边界也确定了是负数所以left++,如果x[p] == 0,那么只用p继续向前移动即可,因为如果前面还有负数,还能将左边界的0交换到中间。

#include <iostream>
using namespace std;
const int maxn = 10;
void sort3p(int* x, int len)
{
  int p = 0;
  int left = 0;
  int right = len-1;

  while(p <= right)
  {
    if(x[p]<0)
    {
      int t = x[left];
      x[left] = x[p];
      x[p] = t;
      left++;
      p++;
    }
    else if(x[p]>0)
    {
      int t = x[right];
      x[right] = x[p];
      x[p] = t;
      right--;
    }
    else
    {
     p++;
    }
  }
}

int main()
{
    //freopen("d:in.txt","r",stdin);
    //freopen("d:testout.txt","w",stdout);
    int x[14] = {25,18,-2,0,16,-5,33,21,0,19,-16,25,-3,0};
    sort3p(x, 14);
    for(int i = 0; i < 14; i++) cout << x[i] << " ";

    return 0;
}

错误票据

简单题不多赘述。

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <sstream>
using namespace std;

int main()
{
    //freopen("d:in.txt","r",stdin);
    //freopen("d:testout.txt","w",stdout);
    int nn;
    cin>>nn;
    getchar();
    int cnt=0;
    int x[10005];
    for(int i=1;i<=nn;i++)
    {
      string s;
      getline(cin,s);
      //cout<<s<<endl;
      stringstream ss;
      ss<<s;
      while(ss>>x[cnt++]) ;
    }
    int n,m;
    sort(x,x+cnt);
    for(int i=1;i<cnt;i++)
    {
      //cout<<x[i]<<endl;
      if(x[i]==x[i-1]) m=x[i];
      else
      {
        if(x[i]-x[i-1]!=1) n=x[i-1]+1;
      }
    }
    cout<<n<<" "<<m<<endl;
    return 0;
}

翻硬币

这道题用bfs做会超时,所以通过找到一个规律来求解。
例如,有两个串,***** ***** 和 o**** o****,第一个硬币不同的位置为1,第二个硬币不同的位置为6,最小翻动次数即为6 - 1 = 5.如果有多段不同的序列,则将不同序列的和相加。

#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;

int main()
{
    //freopen("d:in.txt","r",stdin);
    //freopen("d:testout.txt","w",stdout);
    string s1, s2;
    int start = -1;
    int ans = 0;
    cin >> s1 >> s2;
    for(int i = 0; i < s1.length(); i++)
    {
      if(s1[i] != s2[i])
      {
        if(start == -1)
        {
          start = i;
        }
        else
        {
          ans += (i - start);
          start = -1;
        }
      }
    }
    cout << ans << endl;
    return 0;
}

带分数

直接dfs求出整个解空间,然后找出符合条件的解。
dfs的参数解释:
vis[]数组用来记录当前访问过的数字,确保1-9只使用一次。
divide1,divide2分别是被除数和除数。
dividenum1用来控制被除数位数,假如 整数部分是1,那么分数部分就有8位。dividenum1 = 2,表示得到一个2位的被除数后,开始枚举一个6位的除数。
nowDivideNum1初始化为0,表示当前被除数已经有多少位。当nowDivideNum1 == dividenum1 - 1时, 开始枚举除数。
intger表示带分数的整数部分
nownum表示现在还剩多少位数字没有使用,如果等于0,则说明得到了一个带分数。

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;
const int maxn = 11;
int n;
int ans;
void dfs(bool vis[], int divide1, int divide2, int divideNum1, int nowDivideNum1,  int intger, int nownum)
{


  if(nownum == 0 && intger + divide1/divide2 == n && (divide1/divide2) * divide2 == divide1)
  {
    //cout << intger << " + " << divide1 << "/" << divide2 << endl;
    ans++;
    return ;
  }
  else
  {
    if(nowDivideNum1 < divideNum1)
    {
      for(int i = 1; i <= 9; i++)
      {
        if(!vis[i])
        {
          int tmp = divide1 * 10 + i;
          vis[i] = true;
          dfs(vis, tmp, divide2, divideNum1, nowDivideNum1+1, intger, nownum-1);
          vis[i] = false;
        }
      }
    }
    else
    {
      for(int i = 1; i <= 9; i++)
      {
        if(!vis[i])
        {
          int tmp = divide2 * 10 + i;
          vis[i] = true;
          dfs(vis, divide1, tmp, divideNum1, nowDivideNum1, intger, nownum-1);
          vis[i] = false;
        }
      }
    }
  }
}
int main()
{
    //freopen("d:in.txt","r",stdin);
    //freopen("d:testout.txt","w",stdout);
    bool vis[maxn];
    ans = 0;
    cin >> n;
    for(int i = 1; i <= n; i++)
    {

      memset(vis, false, sizeof(vis));
      int num = i;
      int flag = 1;
      int Count = 0;
      while(num) //判断num是否可以作为带分数的整数部分并且记录整数部分的位数
      {
        if(num%10 == 0 || vis[num%10] == true)
        {
          flag = 0;
          break;
        }
        else
          vis[num%10] = true;
        num /= 10;
        Count++;
      }
      if(flag)
      {
        //cout << "i = " << i << endl;
        for(int j = 1; j <= 8-Count; j++)
        {
          dfs(vis, 0, 0, j, 0, i, 9-Count);
        }
      }
    }
    cout << ans << endl;
    return 0;
}

连号区间数

这道题的数据很水,所以O(n²)的写法也能过, 没有太大意义。

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;
const int maxn = 50005;
int main()
{
    //freopen("d:in.txt","r",stdin);
    //freopen("d:testout.txt","w",stdout);
    int a[maxn];
    int n;
    int ans = 0;
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> a[i];
    for(int i = 1; i <= n; i++)
    {
      int Min = a[i];
      int Max = a[i];
      for(int j = i; j <= n; j++)
      {
        if(i == j)
        {
          ans++;
        }
        else
        {
          Min = min(Min, a[j]);
          Max = max(Max, a[j]);
          if(Max - Min == j - i) ans++;
        }
      }
    }
    cout << ans << endl;
    return 0;
}

2014年省赛真题

啤酒与饮料

三个小数都扩大十倍变成整数运算。

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;
const int maxn = 50005;
int main()
{
    //freopen("d:in.txt","r",stdin);
    //freopen("d:testout.txt","w",stdout);
    int beer = 0;
    int drink = 1;
    for(;; drink++)
      for(beer = 0; beer < drink; beer++)
    {
      if(drink*19 + beer*23 == 823)
      {
        cout << "beer = " << beer << " drink = " << drink << endl;
        return 0;
      }
    }
    //return 0;
}

切苗条

找规律,切n次有 pow(2, n) + 1段。

#include <iostream>
#include <math.h>
using namespace std;
const int maxn = 50005;
int main()
{
    //freopen("d:in.txt","r",stdin);
    //freopen("d:testout.txt","w",stdout);

    cout << (int)pow(2,10) + 1 << endl;
    return 0;
}

李白打酒

dfs所有结果就行。

#include <iostream>
#include <math.h>
using namespace std;
int ans = 0;
void dfs(int beer, int shop, int flower)
{
  if(beer <= 0) return ;
  if(!shop && flower == 1)
  {
    if(beer - 1 == 0)
      ans++;
    return;
  }
  if(shop > 0) dfs(beer*2, shop-1, flower);
  if(flower > 0) dfs(beer-1, shop, flower-1);
}
int main()
{
    //freopen("d:in.txt","r",stdin);
    //freopen("d:testout.txt","w",stdout);
    dfs(2, 5, 10);
    cout << ans << endl;
    return 0;
}

奇怪的分式

不要用分数的除法来比较,会丢失精确度。先算出两个分数的最简式,然后分子分母都相同则分数相同。

#include <iostream>
#include <math.h>
using namespace std;
int gcd(int a, int b)
{
  return (!b)? a:gcd(b, a%b);
}
int main()
{
    //freopen("d:in.txt","r",stdin);
    //freopen("d:testout.txt","w",stdout);
    int ans = 0;
    for(int son1 = 1; son1 <= 9; son1++)
      for(int mother1 = 1; mother1 <= 9; mother1++)
      {
        if(son1 == mother1) continue;
        for(int son2 = 1; son2 <= 9; son2++)
          for(int mother2 = 1; mother2 <= 9; mother2++)
          {
            if(son2 == mother2) continue;

            int son3 = son1*10 + son2;
            int mother3 = mother1*10 + mother2;
            int son4 = son1 * son2;
            int mother4 = mother1 * mother2;
            int gcd3 = gcd(son3, mother3);
            int gcd4 = gcd(son4, mother4);

            son3 /= gcd3;
            mother3 /= gcd3;
            son4 /= gcd4;
            mother4 /= gcd4;

            if(son3 == son4 && mother3 == mother4) ans++;
          }
      }
    cout << ans << endl;

    return 0;
}

打印图形

考虑rank = 6 的情况,先把打印出的图片看作三个大的三角形,上面一个,下面两个。然后给出的递归式打印的是下面两个,因此只要处理上面的一个大三角形。每次输入的都是大三角形的左上顶点。

#include <iostream>
#include <math.h>
#include <stdio.h>
using namespace std;

#define N 70

void f(char a[][N], int Rank, int row, int col)
{
  //cout << "Rank = " << Rank << " row = " << row << " col = " << col << endl;
  if(Rank == 1)
  {
    //cout << " row = " << row << " col = " << col << endl;
    a[row][col] = '*';
    return;
  }

  int w = 1;
  int i;
  for(i = 0; i< Rank-1; i++) w *= 2;

  f(a, Rank-1, row, col+w/2); //填空
  f(a, Rank-1, row+w/2, col); // a, 5, 16, 0
  f(a, Rank-1, row+w/2, col+w); // a, 5, 16, 32

}

int main()
{
    //freopen("d:in.txt","r",stdin);
    //freopen("d:testout.txt","w",stdout);
    char a[N][N];
    int i, j;
    for(i = 0;i < N;i++)
      for(j = 0;j < N;j++) a[i][j] = ' ';

    f(a, 6, 0, 0);

    for(i = 0; i < N; i++)
    {
      for(j = 0; j < N; j++) printf("%c", a[i][j]);
      printf("\n");
    }

    return 0;
}

地宫取宝

这题用普通的dfs会超时,需要记忆化搜索。
用一个四维数组cache[x][y][Maxci][choicenum]表示一个点在取MaxCi值时的choicenum种数,从而避免了一些情况的重复搜索。

#include <iostream>
#include <math.h>
#include <stdio.h>
#include <string.h>
using namespace std;
const int maxn = 55;
const long long mod = 1000000007;

int n, m, k;
int Map[maxn][maxn];
int cache[maxn][maxn][14][13];
int dx[2] = {0, 1};
int dy[2] = {1, 0};

long long dfs(int x, int y, int MaxCi, int choicenum)
{
  long long ans = 0;
  //cout << "x = " << x << " y = " << y << " choicenum = " << choicenum << endl;
  if(cache[x][y][MaxCi+1][choicenum] != -1) return cache[x][y][MaxCi+1][choicenum];

  if(x == n && y == m)
  {
    if(choicenum == k || (choicenum == k-1 && Map[n][m] > MaxCi))
    {
      ans = (ans+1) % mod;
      return ans;
    }

    return 0;
  }

  for(int i = 0; i < 2; i++)
  {
    int xx = x + dx[i];
    int yy = y + dy[i];
    if(xx <= n && yy <= m)
    {
      if(Map[x][y] > MaxCi)
        ans += dfs(xx, yy, Map[x][y], choicenum+1);
      ans += dfs(xx, yy, MaxCi, choicenum);
    }
  }

  cache[x][y][MaxCi+1][choicenum] = ans % mod;

  return ans % mod;
}

int main()
{
    //freopen("d:in.txt","r",stdin);
    //freopen("d:testout.txt","w",stdout);
    cin >> n >> m >> k;
    for(int i = 1; i <= n; i++)
      for(int j = 1; j <= m; j++) cin >> Map[i][j];
    memset(cache, -1, sizeof(cache));
    cout << dfs(1, 1, -1, 0) << endl;

    return 0;
}

六角填数

按下图方式处理图形:图中黑子数字编号代表搜索顺序,蓝色数字代表六条直线的编号,用来计算直线之和,然后dfs即可。

#include <iostream>
#include <math.h>
#include <stdio.h>
#include <string.h>
using namespace std;
int line[6];
int ans;
bool vis[13];
int Map[9][6] = {
  {1, 0, 0, 1, 0, 0},
  {1, 0, 0, 0, 1, 0},
  {0, 1, 0, 0, 1, 0},
  {0, 1, 0, 0, 0, 1},
  {0, 0, 1, 0, 0, 1},
  {0, 0, 1, 1, 0 ,0},
  {1, 1, 0, 0, 0, 0},
  {0, 0, 0, 0, 1, 1},
  {0, 0, 0, 1, 0, 1}
};

void dfs(int num)
{
  if(num == 0)
  {
    int flag = 1;
    for(int i = 0; i < 5; i++)
    {
      if(line[i] != line[i+1])
      {
        flag = 0;
        break;
      }
    }
    if(flag)
      cout << ans << endl;
    return ;
  }

  for(int i = 1; i <= 12; i++)
  {
    if(!vis[i])
    {
      if(num == 4) ans = i;
      vis[i] = true;
      for(int j = 0; j < 6; j++)
      {
        if(Map[9-num][j])
          line[j] += i;
      }

      dfs(num-1);

      vis[i] = false;
      for(int j = 0; j < 6; j++)
      {
        if(Map[9-num][j])
          line[j] -= i;
      }
    }
  }
}

void init()
{
  memset(vis, false, sizeof(vis));
  memset(line, 0, sizeof(line));
  vis[1] = vis[3] = vis[8] = true;
  line[0] = 8;
  line[1] = 3;
  line[2] = 11;
  line[3] = line[4] = 1;
}
int main()
{
    //freopen("d:in.txt","r",stdin);
    //freopen("d:testout.txt","w",stdout);

    init();
    dfs(9);
    return 0;
}

史丰收运算

根据填空部分while循环的代码来看,r变量等于0时继续循环,r变量小于0时满足大于某一位的条件,所以填空部分处理的应该是r变量小于0 的时候的返回值。例如取900000和840000两个值时,i都是从5开始循环递减。900000> 857142,满足大于的条件返回i+1即6,而840000< 857142因此返回 i 就行。

#include <iostream>
#include <math.h>
#include <stdio.h>
#include <string.h>
using namespace std;
//计算个位
int ge_wei(int a)
{
    if(a % 2 == 0)
        return (a * 2) % 10;
    else
        return (a * 2 + 5) % 10;
}

//计算进位
int jin_wei(char* p)
{
    char* level[] = {
        "142857",
        "285714",
        "428571",
        "571428",
        "714285",
        "857142"
    };

    char buf[7];
    buf[6] = '\0';
    strncpy(buf,p,6);

    int i;
    for(i = 5; i >= 0; i--)
    {
        int r = strcmp(level[i], buf);
        if(r < 0) return i+1;
        while(r == 0)
        {
            p += 6;
            strncpy(buf,p,6);
            r = strcmp(level[i], buf);

            if(r < 0) return i+1;

            if(r > 0) return i;//填空
        }
    }

    return 0;
}

//多位数乘以7
void f(char* s)
{
    int head = jin_wei(s);
    if(head > 0) printf("%d", head);

    char* p = s;
    while(*p)
    {
        int a = (*p-'0');
        int x = (ge_wei(a) + jin_wei(p+1)) % 10;
        printf("%d",x);
        p++;
    }

    printf("\n");
}

int main()
{
    //freopen("d:in.txt","r",stdin);
    //freopen("d:testout.txt","w",stdout);
    f("428571428571");
    f("34553834937543");

    return 0;
}

蚂蚁感冒

#include <iostream>
#include <math.h>
#include <stdio.h>
#include <string.h>
using namespace std;
struct point
{
	int x;
	bool a;
	int t;
}p[maxn];

bool cmp(point p1,point p2)
{
	return p1.x<p2.x;
}
int main()
{
    //freopen("d:in.txt","r",stdin);
    //freopen("d:testout.txt","w",stdout);
    int n;
    cin >> n;
    point s;
    cin >> p[1].x;
    if(p[1].x < 0)
    {
      p[1].x = -p[1].x;
      p[1].a = true;
      p[1].t = -1;
    }
    else 
    {
      p[1].a = true;
      p[1].t =1;
    }
    for(int i = 2;i <= n;i++)
    {
      cin >> p[i].x;
      if(p[i].x < 0)
      {
        p[i].x = -p[i].x;
        p[i].a = false;
        p[i].t = -1;
      }
      else 
      {
        p[i].a = false;
        p[i].t = 1;
      }
    }
    sort(p+1, p+1+n, cmp);
    while(1)
    {
      int Min = 999;
      int start;
      for(int i = 2;i <= n;i++)
      {
        if(p[i-1].t == 1 && p[i].t == -1 && (p[i].x-p[i-1].x) < Min) 
        {
          Min = p[i].x-p[i-1].x;
          start = i-1;
        }
      }
      if(Min == 999) break;
      else 
      {
        for(int i = 2;i <= n;i++)
        {
          if(p[i-1].t == 1 && p[i].t == -1 && (p[i].x-p[i-1].x) == Min) 
          {
            if(p[i-1].a == true || p[i].a == true)
              p[i-1].a = p[i].a = true;
              
            p[i-1].t = -p[i-1].t;
            p[i].t = -p[i].t;
          }
          else if(i != start && i != start + 1)
          {
            p[i].x += p[i].t * Min;					
          }
        }
        if(start != 1) p[1].x += p[1].t * Min;	
      }
    }

    int ans = 0;
    for(int i = 1;i <= n;i++)
    if(p[i].a == true) ans++;

    cout << ans << endl;
    return 0;
}

小朋友排队

这道题有冒泡排序的的味道,但用冒泡排序会超时。看大部分博客都是用树状数组做,本人只学过线段树,这里就用线段树做。
首先要明白这道题就是找逆序对的个数,对于用线段树的做法,那么就是遍历数组中的每一个数,从这个数往后找所有比它小的数(这样就一定要交换一次),从这个数往前找所有比它大的数(同样是逆序对)。所以先建一次树,然后再用一个数组记录第一种情况,对于每个数Hi, 就用线段树统计【1, Hi-1】区间内的个数,然后再建一次树处理第二种情况。
注意用线段树做本题的坑点
(1) 用于记录逆序对的数组必须是long long型,不然计算不高兴值时会超出范围。
(2) 身高值可以为0,因此每次数组的身高都加1,便于建立线段树。
(3) 遇到身高为1(身高为0的小朋友加了1后)的数据,需要跳过,不然线段树query函数会出错。而且continue不能放在for循环开始,应该等到update后再continue。
下面给出一个样例。
在这里插入图片描述

#include <iostream>
#include <math.h>
#include <stdio.h>
#include <string.h>
using namespace std;
const int maxn = 100000;
struct node
{
  int l,r;
  int sum;
}T[maxn*10*4+5];
int Hi[maxn*10+5];
int Hx[maxn+5];
long long cnt[maxn+5]; // 1
long long ans;
void build(int left, int right, int num)
{
  T[num].l = left;
  T[num].r = right;
  if(left == right)
  {
    //cout << "left = " << left << " Hi[left] = " << Hi[left] << endl;
    T[num].sum = Hi[left];
    return;
  }
  int mid = (left + right) / 2;

  build(left, mid, 2*num);
  build(mid+1, right, 2*num+1);

  T[num].sum = T[2*num].sum + T[2*num+1].sum;
}

void update(int x, int num)
{
  //cout << "T[num].l = " << T[num].l << " T[num].r = " << T[num].r << " num = " << num << endl;
  T[num].sum--;

  if(T[num].l == T[num].r) return ;

  int mid = (T[num].l + T[num].r) / 2;

  if(x <= mid)
    update(x, 2*num);
  else
    update(x, 2*num+1);
}

void query(int x, int y, int num)
{

  if(x == T[num].l && y == T[num].r)
  {
    ans += T[num].sum;
    return ;
  }

  int mid = (T[num].l + T[num].r) / 2;

  if(y <= mid)
    query(x, y, 2*num);
  else if(x > mid)
    query(x, y, 2*num+1);
  else
  {
    query(x, mid, 2*num);
    query(mid+1, y, 2*num+1);
  }
}

void Search(int num)
{
  cout << "left = " << T[num].l << " right = " << T[num].r << " sum = " << T[num].sum << " num = " << num << endl;

  if(T[num].l == T[num].r) return;
  Search(2*num);
  Search(2*num+1);
}
int main()
{
    //freopen("d:in.txt","r",stdin);
    //freopen("d:testout.txt","w",stdout); 
    int n;
    memset(Hi, 0, sizeof(Hi));
    memset(cnt, 0, sizeof(cnt));
    cin >> n;
    for(int i = 1; i <= n; i++)
    {
      cin >> Hx[i];
      Hx[i] += 1;//2
      Hi[Hx[i]]++;
    }

    build(1, maxn*10+5, 1);
    //Search(1);
    for(int i = 1; i <= n; i++)
    {
      ans = 0;
      update(Hx[i], 1);
      if(Hx[i] == 1) continue; // 3
      //if(i == 7) Search(1);
      query(1, Hx[i]-1, 1);
      cnt[i] += ans;
      //cout << "cnt[i] = " << cnt[i] << " Hx[i] = " << Hx[i] << endl;
    }

    build(1, maxn*10+5, 1);
    for(int i = n; i >= 1; i--)
    {
      ans = 0;
      update(Hx[i], 1);
      query(Hx[i]+1, maxn*10+5, 1);
      cnt[i] += ans;
      //cout << "cnt[i] = " << cnt[i] << endl;
    }

    ans = 0;
    for(int i = 1; i <= n; i++)
      ans += (1 + cnt[i])*cnt[i] / 2;

    cout << ans << endl;

    return 0;
}

2015年省赛真题

奖券数目

#include <iostream>
#include <math.h>
#include <stdio.h>
#include <string.h>
using namespace std;
const int maxn = 100000;

int main()
{
    //freopen("d:in.txt","r",stdin);
    //freopen("d:testout.txt","w",stdout);
    int sum = 0;
    for(int i = 10000; i <= 99999; i++)
    {
      if(i >= 40000 && i <= 49999) continue;
      int tmp = i;
      int flag = 1;
      while(tmp)
      {
        if(tmp % 10 == 4)
        {
          flag = 0;
          break;
        }
        tmp /= 10;
      }
      if(flag) sum++;
    }
    cout << sum << endl;
    return 0;
}

星系炸弹

2017-08-05.

三羊献瑞

枚举。

  #include <iostream>
  #include <math.h>
  #include <stdio.h>
  #include <string.h>
  using namespace std;

  int main()
  {
      //freopen("d:in.txt","r",stdin);
      //freopen("d:testout.txt","w",stdout);
      for(int A = 1; A <= 9; A++)
      {
        for(int B = 0; B <= 9; B++)
        {
          if(A == B) continue;
          for(int C = 0; C <= 9; C++)
          {
            if(A == C || B == C) continue;
            for(int D = 0; D <= 9; D++)
            {
              if(A == D || B == D || C == D) continue;
              for(int E = 1; E <= 9; E++)
              {
                if(A == E || B == E || C == E || D == E) continue;
                for(int F = 0; F <= 9; F++)
                {
                  if(A == F || B == F || C == F || D == F || E == F) continue;
                  for(int G = 0; G <= 9; G++)
                  {
                    if(A == G || B == G || C == G || D == G || E == G || F == G) continue;
                     for(int H = 0; H <= 9; H++)
                    {
                      if(A == H || B == H || C == H || D == H || E == H || F == H || G == H) continue;
                      int add1 = A*1000 + B*100 + C*10 + D;
                      int add2 = E*1000 + F*100 + G*10 + B;
                      int add3 = E*10000 + F*1000 + C*100 + B*10 + H;
                      //cout << "add1 = " << add1 << " add2 = " << add2 << " add3 = " << add3 << endl;
                      if(add1 + add2 == add3)
                      {
                        cout << "  " << A << " " << B << " " << C << " " << D << endl;
                        cout << "+ " << E << " " << F << " " << G << " " << B << endl;
                        cout << E << " " << F << " " << C << " " << B << " " << H << endl;
                        return 0;
                      }
                    }

                  }
                }
              }
            }
          }
        }
      }
      return 0;
  }

格子里输出

%*s表示输出字符串至少有X个长度,不足的长度补空格。

#include <iostream>
#include <math.h>
#include <stdio.h>
#include <string.h>
using namespace std;

void StringInGrid(int width, int height, const char* s) // 20 6 abcd1234 //8
{
    int i,k;
    char buf[1000];
    strcpy(buf, s);
    if(strlen(s) > width - 2) buf[width-2] = 0;

    printf("+");
    for(i = 0; i < width - 2; i++) printf("-");
    printf("+\n");

    for(k=1; k < (height - 1) / 2; k++)
    {
        printf("|");
        for(i = 0; i < width - 2; i++) printf(" ");
        printf("|\n");
    }

    printf("|");

    printf("%*s%s%*s",(width - 2 - strlen(buf)) / 2, "",buf, (width - 1 - strlen(buf)) / 2, "");  //填空

    printf("|\n");

    for(k = (height - 1) / 2 + 1; k < height - 1; k++)
    {
        printf("|");
        for(i = 0; i < width - 2; i++) printf(" ");
        printf("|\n");
    }

    printf("+");
    for(i = 0; i < width-2; i++) printf("-");
    printf("+\n");
}
int main()
{
    //freopen("d:in.txt","r",stdin);
    //freopen("d:testout.txt","w",stdout);
    StringInGrid(20, 6, "abcd1234");
    return 0;
}

九数组分数

典型回溯问题,递归前改变值,递归后将值变回去。

#include <iostream>
#include <math.h>
#include <stdio.h>
#include <string.h>
using namespace std;

void test(int x[])
{
    int a = x[0]*1000 + x[1]*100 + x[2]*10 +x[3];
    int b = x[4]*10000 + x[5]*1000 + x[6]*100 +x[7]*10 + x[8];
    if(a * 3 == b)
        printf("%d / %d\n", a,b);
}
void f(int x[],int k)
{
    int i,t;
    if(k >= 9)
    {
        test(x);
        return;
    }
    for(i = k; i < 9; i++)
    {
        {t = x[k];x[k] = x[i];x[i] = t;}
        f(x,k+1);
        {t = x[k];x[k] = x[i];x[i] = t;}// 填空处
    }
}
/*
1,2,3…9 这九个数字组成一个分数,其值恰好为1/3,如何组法?
下面的程序实现了该功能,请填写划线部分缺失的代码。
*/
int main()
{
    //freopen("d:in.txt","r",stdin);
    //freopen("d:testout.txt","w",stdout);
    int x[] = {1,2,3,4,5,6,7,8,9};
    f(x,0);
    return 0;
}

加法变乘法

枚举。

#include <iostream>
#include <math.h>
#include <stdio.h>
#include <string.h>
using namespace std;
const int maxn = 50;

int main()
{
    //freopen("d:in.txt","r",stdin);
    //freopen("d:testout.txt","w",stdout)
    for(int i = 1; i < maxn-1; i++)
    {
      for(int j = i+2; j < maxn-1; j++)
      {
        int sum = 1225 + j*(j+1) - j - (j+1) + i*(i+1) - i - (i+1);
        if(sum == 2015)
          cout << i << endl;
      }
    }
    return 0;
}

移动距离

#include <iostream>
#include <math.h>
#include <stdio.h>
#include <string.h>
using namespace std;
int abs(int a, int b)
{
  if(a > b) return a-b;
  else return b-a;
}
int main()
{
    //freopen("d:in.txt","r",stdin);
    //freopen("d:testout.txt","w",stdout)
    int w, m, n;
    while(~scanf("%d%d%d", &w, &m, &n))
    {
      int row1, col1;
      int row2, col2;

      if(m/w*w != m) row1 = m/w + 1;
      else row1 = m/w;

      if(n/w*w != n) row2 = n/w + 1;
      else row2 = n/w;

      if(row1%2 == 0)
        col1 = w - (m-1)%w;
      else
        col1 = (m%w == 0? w:m%w);

      if(row2%2 == 0)
        col2 = w - (n-1)%w;
      else
        col2 = (n%w == 0? w:n%w);
      //cout << "row1 = " << row1 << " row2 = " << row2 << " col1 = " << col1 << " col2 = " << col2 << endl;
      cout << abs(row1, row2) + abs(col1, col2) << endl;
    }

    return 0;
}

  • 9
    点赞
  • 74
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值