2017 華東師範計算機系暑期夏令營機考

題目鏈接<-請點擊

題目

A.不等式

B. 1 的個數最多的整數

C. 打印

D. 十億分考

E. 有錢人買鑽石

F. 送分題


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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章