2017华东师范大学暑期夏令营机考试题

文章提供了六个编程问题的解决方案,涉及不等式的边界值判断,二进制表示中1的个数优化,动态规划求解最小代价,用连分数转换处理小数,以及使用深度优先搜索和贪心策略解决硬币找零问题,并利用莫队算法处理离线查询。这些问题展示了不同的算法和数据结构在解决问题中的应用。
摘要由CSDN通过智能技术生成

题目链接<-请点击
A.不等式
将不等式的边界值存起来,然后依次进行判断即可。

#include <bits/stdc++.h>
 
using namespace std;
const int maxn = 200 + 10;
typedef long long LL;
 
int a[maxn], b[maxn];
string op[maxn];
 
int main()
{
  int n;
  scanf("%d",&n);
  string x;
  for(int i = 1; i <= n; i++)
  {
    cin >> x;
    cin >> op[i];
    scanf("%d", &a[i]);
    //cout << x << op[i] << a[i] << endl;
    if(op[i] == "<") b[i] = a[i] - 1;
    else if(op[i] == ">") b[i] = a[i] + 1;
    else b[i] = a[i];
  }
  int ans = 0;
  for(int i = 1; i <= n; i++)
  {
      int res = 0;
      for(int j = 1; j <= n; j++)
      {
          if(op[j] == "=" && b[i] == a[j]) res ++;
          else if(op[j] == "<" && b[i] < a[j]) res ++;
          else if(op[j] == ">" && b[i] > a[j]) res ++;
          else if(op[j] == "<=" && b[i] <= a[j]) res++;
          else if(op[j] == ">=" && b[i] >= a[j]) res++;
      }
      ans = max(ans, res);
    }
  printf("%d\n",ans);
  return 0;
}

B. 1 的个数最多的整数
首先将a,b 都化为二进制形式,然后对于a的二进制形式从低位向高位进行遍历,如果该位为0则考虑变为1后是否会大于b,不会大于b则将其变为1后继续判断,否则停止遍历。原理:如果高位可变为1则低位更加能变成1。

#include <bits/stdc++.h>
 
using namespace std;
const int maxn = 1e7 + 10;
typedef long long LL;
LL a,b;
 
string change(LL x)
{
  string res;
  while(x)
  {
    res += (x%2) + '0';
    x >>= 1;
  }
  return res;
}
 
int main()
{
  int cas = 0,T;
  scanf("%d",&T);
  while(T--)
  {
  scanf("%lld%lld",&a,&b);
  string sa,sb;
  sa = change(a);
  sb = change(b);
  // cout << sa << endl;
  // cout << sb << endl;
  LL tmp = 1;
  for(int i = 0; i < sb.size(); i++, tmp <<= 1)
      if((i >= sa.size() || sa[i] == '0') && a + tmp <= b)
        a += tmp;
  printf("Case %d: %lld\n",++cas,a);
}
  return 0;
}

C. 打印
线性DP, 通过插入、删除、复制三个操作进行状态转移。

#include <bits/stdc++.h>
 
using namespace std;
const int maxn = 1e7 + 10;
typedef long long LL;
LL dp[maxn];
 
int main()
{
  int n,x,y;
  scanf("%d%d%d", &n, &x, &y);
  for(int i = 1; i <= n; i++)
    if(i % 2 == 0)
      dp[i] = min(dp[i-1] + x, dp[i/2] + y);
    else dp[i] = min(dp[i-1] + x, min(dp[(i-1)/2]+y+x, dp[(i+1)/2]+y+x));
  printf("%lld\n",dp[n]);
  return 0;
}

D. 十亿分考
直接暴力化分数会WA或者TLE, 考虑通过连分数来进行,小数化连分数、连分数再化分数。

#include <bits/stdc++.h>
 
using namespace std;
const int maxn = 200 + 10;
typedef long long LL;
 
double n;
vector<int>cnt;
 
LL gcd(LL a, LL b)
{
  return b == 0? a: gcd(b, a%b);
}
 
double cal()
{
  double res = 0;
  for(int i = cnt.size()-1; i >= 0; i--)
  {
    res += cnt[i];
    res = 1/res;
  }
  return res;
}
 
int main()
{
  double x;
  cin >> n;
  x = n;
  double y = 0;
  while(fabs(n-cal()) > 0.5*1e-15)
  {
    x = 1/x;
    cnt.push_back(int(x));
    x -= int(x);
  }
  // for(int i = 0; i < cnt.size(); i++)
  //   cout << cnt[i] << endl;
  LL p = 0,q = 1;
  for(int i = cnt.size()-1; i >= 0; i--)
    {
      p += q*cnt[i];
      swap(p,q);
    }
  // cout << p << q << endl;
  LL g = gcd(p,q);
  printf("%lld %lld\n",p/g, q/g);
   // printf("%.15f\n",1.0*p/q);
  return 0;
}

E. 有钱人买钻石
使用DFS加贪心,DFS的每一层为一种硬币,因为要总重量(数量)最大,所以从小面额到大面额DFS。DFS从上一层转移到下一层时,使用的本层硬币数为[low,high], high = min(所需要的, 所有的)的数量,low = max(0,high - 5); high 很容易理解,很合理,而low为什么取high-25 ? 最大面额为25, 当前面的某一个面额装换成后面的面额时,最多消耗25个小面额即可。

(如果前面懂了,后面可以不用看了)可以分两个情况来思考一下,一个是如果high = 所有的,说明当前面额不足,所以可以让后面的来补缺口,这个缺口一定视为x+y*大面额,0<=x<=25。如果high = 所需要的,说明当前充足,按理说可以取了所需要的到下一步, 但是可能会出现这样一种情况,当前剩余25,现在面额为10的有三张,为25的有一张,先考虑面额为10的,如果取了两张20的就会导致Impossible。

#include<bits/stdc++.h>
 
using namespace std;
int p, v[4], c[4] = {1 ,5, 10, 25};
int ans = -1;
 
bool dfs(int id, int num, int sum)
{
  // printf("%d %d %d\n",id, num, sum);
  if(sum == p) {ans = num; return true;}
  if(id >= 4 || sum > p) return false;
  int high = min((p-sum)/c[id], v[id]);
  int low = max(0,high-25);
  for(int i = high; i >= low; i--)
    if(dfs(id+1, num + i, sum + i * c[id])) return true;
  return false;
}
 
int main()
{
  scanf("%d%d%d%d%d",&p, &v[0], &v[1], &v[2], &v[3]);
  if(dfs(0,0,0)) printf("%d\n", ans);
  else printf("Impossible\n");
  return 0;
}

F. 送分题
离线查询,使用莫队算法可解。莫队算法讲解 <-请点击

因为数据范围为5e5, 使用莫队nsqrt(n) 差不多刚好,和bzoj 1878 HH的项链 大同小异。

#include<bits/stdc++.h>
 
using namespace std;
const int maxn = 5e5+10;
int n,m,block;
int a[maxn],b[maxn],l[maxn],r[maxn],num[maxn],ans[maxn];
int cl = 1,cr=0,cnt = 0;
map<int,int>mp;
bool cmp(int x, int y)
{
  return (l[x]/block) ^ (l[y]/block) ? l[x] < l[y] : r[x] < r[y];
}
 
void add(int x)
{
  if(num[a[x]] == 2) cnt--;
  if(++num[a[x]] == 2) cnt++;
}
void del(int x)
{
  if(num[a[x]] == 2) cnt--;
  if(--num[a[x]] == 2) cnt++;
}
 
int main()
{
    scanf("%d%d",&n, &m);
    block = sqrt(n);
    int tot = 0;
    for(int i = 1; i <= n; i++)
    {
      scanf("%d",&a[i]);
      if(mp.count(a[i]) == 0) mp[a[i]] = tot++;
      a[i] = mp[a[i]];
    }
    memset(num,0,sizeof(num));
    // for(int i = 1; i <= n; i++) printf("%d ",a[i]);
    // printf("\n");
    for(int i = 0; i < m; i++) {scanf("%d%d",&l[i],&r[i]);b[i] = i;}
    sort(b,b+m,cmp);
    for(int i = 0; i < m; i++)
    {
      while(cl < l[b[i]]) del(cl++);
      while(cl > l[b[i]]) add(--cl);
      while(cr < r[b[i]]) add(++cr);
      while(cr > r[b[i]]) del(cr--);
      // printf("\n");
      // printf("%d %d %d %d\n",l[b[i]],r[b[i]],cl,cr);
      // for(int j = 0; j < tot; j++) printf("%d ",num[j]);
      // printf("\n");
      ans[b[i]] = cnt;
    }
    for(int i = 0; i < m; i++) printf("%d\n",ans[i]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值