补题:西南民族大学第十一届程序设计竞赛(同步赛)

比赛入口

B 都说小镇的切糕贵

做法:题意是要求一个字符串中能包含该串出现所有字符的最小长度,是滑动窗口技巧题目的典型例题。
具体滑动窗口实现:
如果左边界遇到 与当前s[i]相同且s[i]之前出现过 的,更新最小窗口长度res = min(res, i-l+1);
如果左边界遇到 与当前s[i]相同且s[i]之前未出现过 的,把flag置为1,处理完l后强制更新res = i - l + 1。

代码

#include<bits/stdc++.h>
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
using namespace std;
typedef long long LL;
typedef pair<LL, int> pli;
typedef pair<int, int> pii;
typedef pair<LL, LL> pll;
typedef map<char, int> mci;
typedef map<string, int> msi;
template<class T>
void read(T &res) {
  int f = 1; res = 0;
  char c = getchar();
  while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
  while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); }
  res *= f;
}
int main() {
  fio
  int n; cin >> n;
  string s; cin >> s;
  int len = s.size();
  unordered_map<char, int> vis;
  vis.clear();
  int l = 0, res = n;
  for(int i = 0; i < len; ++i) {
    int flag = 0;
    if(!vis[s[i]]) flag = 1; //与当前s[i]相同且s[i]之前未出现过
    vis[s[i]]++;
    while(vis[s[l]] > 1) {
      vis[s[l]]--; l++;
    }
    if(flag) res = i - l + 1;
    else res = min(res, i - l + 1);
  }
  printf("%d\n", res);
  return 0;
}

C Guard the empire

做法:题意是要求最少需要多少个半径为r的圆(圆心都在x坐标上),能覆盖住n个给定坐标的点。做法就是找到每个圆能够取到的圆心位置的区间,再贪心找最少有多少个点能将所有区间都部分覆盖。

代码

#include<bits/stdc++.h>
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
using namespace std;
typedef long long LL;
typedef pair<LL, int> pli;
typedef pair<int, int> pii;
typedef pair<LL, LL> pll;
typedef pair<double, double> pdd;
typedef map<char, int> mci;
typedef map<string, int> msi;
template<class T>
void read(T &res) {
  int f = 1; res = 0;
  char c = getchar();
  while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
  while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); }
  res *= f;
}
const int N = 1003;
struct Qujian {
  int l, r;
  bool operator < (const Qujian &c) const {
    if(l != c.l) return l < c.l;
    return r < c.r;
  }
}qj[N];
double toQj(double y, double r) {
  return sqrt(r*r - y*y);
}
int main() {
  int n, c = 0;
  double r;
  while(scanf("%d%lf", &n, &r), n || r) {
    double x, y, cha;
    int flag = 1;
    for(int i = 0; i < n; ++i) {
      scanf("%lf%lf", &x, &y);
      if(y > r) {   //如果超出了圆能表示的范围
        flag = 0; continue;
      }
      cha = toQj(y, r);
      //找出可以覆盖住该点的圆心范围
      qj[i].l = x - cha; qj[i].r = x + cha;
    }
    if(!flag) {
      printf("Case %d: %d\n", ++c, -1);
    } else {
      //贪心找能覆盖住所有点的圆个数
      sort(qj, qj+n);
      double mid = qj[0].r;
      int res = 1;
      for(int i = 1; i < n; ++i) {
        if(qj[i].l > mid) {
          mid = qj[i].r; res++;
        } else if (qj[i].r < mid) {
          mid = qj[i].r;
        }
      }
      printf("Case %d: %d\n", ++c, res);
    }
  }
  return 0;
}

H Magic necklace

做法:有一串标号1~n的数字,要求每个数字不相邻的方案数,因为数字很小,直接上暴力预处理即可,这里用了next_permutation函数。

代码

#include<bits/stdc++.h>
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
using namespace std;
typedef long long LL;
typedef pair<LL, int> pli;
typedef pair<int, int> pii;
typedef pair<LL, LL> pll;
typedef map<char, int> mci;
typedef map<string, int> msi;
template<class T>
void read(T &res) {
  int f = 1; res = 0;
  char c = getchar();
  while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
  while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); }
  res *= f;
}
int res[15], mid[15], n;
int check(int n) {
  for(int i = 1; i <= n; ++i) {
    if(fabs(mid[i+1] - mid[i]) == 1) return 0;
  }
  return 1;
}
int main() {
  //暴力预处理
  res[1] = 1; res[2] = 0;
  for(int i = 3; i <= 11; ++i) {
    for(int j = 1; j <= i; ++j) mid[j] = j;
      mid[i+1] = mid[1];
      while(next_permutation(mid+2, mid+i+1)) {
        if(check(i)) res[i]++;
      }
      res[i] = res[i] / 2;
  }
  int t; scanf("%d", &t);
  while(t--) {
    scanf("%d", &n);
    printf("%d\n", res[n]);
  }
  return 0;
}

I 恋爱之子

做法:一些线段,所有相交的线段成为一个集合,要求有多少个集合,几何板子——判断两条线段是否相交,再用并查集即可。

代码

#include<bits/stdc++.h>
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
using namespace std;
typedef long long LL;
typedef pair<LL, int> pli;
typedef pair<int, int> pii;
typedef pair<LL, LL> pll;
typedef map<char, int> mci;
typedef map<string, int> msi;
template<class T>
void read(T &res) {
  int f = 1; res = 0;
  char c = getchar();
  while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
  while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); }
  res *= f;
}
const int N = 4003;
struct Dian {  //点
  LL x, y;
};
struct Xian {  //线
  Dian s, e;
} xian[N];
double mul(Dian a, Dian b, Dian c) {  //向量叉积
  return ((double)(b.x-a.x) * (c.y-a.y) - (double)(c.x-a.x) * (b.y-a.y));
}
int isJiao(Xian a, Xian b) {  //判断两个线段是否相交
  if( min(a.s.x, a.e.x) <= max(b.s.x, b.e.x) &&
      max(a.s.x, a.e.x) >= min(b.s.x, b.e.x) &&
      min(a.s.y, a.e.y) <= max(b.s.y, b.e.y) &&
      max(a.s.y, a.e.y) >= min(b.s.y, b.e.y) &&
      mul(b.s, a.s, b.e) * mul(b.s, b.e, a.e) >= 0 &&
      mul(a.s, b.s, a.e) * mul(a.s, a.e, b.e) >= 0 )
    return 1;
  return 0;
}
int a[N];
int Find(int x) {
  return a[x] == x ? x : a[x] = Find(a[x]);
}
void Merge(int x, int y) {
  int fx = Find(x), fy = Find(y);
  if(fx != fy) {
    a[fy] = fx;
  }
}
int main() {
  int n; scanf("%d", &n);
  for(int i = 0; i < n; ++i) {
    scanf("%lld%lld%lld%lld", &xian[i].s.x, &xian[i].s.y, &xian[i].e.x, &xian[i].e.y);
    a[i] = i;
  }
  for(int i = 0; i < n - 1; ++i) {
    for(int j = i + 1; j < n; ++j) {
      if(isJiao(xian[i], xian[j])) Merge(i, j);
    }
  }
  int res = 0;
  for(int i = 0; i < n; ++i) {
    if(a[i] == i) res++;
  }
  printf("%d\n", res);
  return 0;
}


K 集训队的依赖关系

做法:由一棵无根树建立超级源点0,再对这棵树进行树形dp,现在还是对树形dp很迷,等彻底学会再来写一篇树形dp专题,咕咕咕~

代码

#include<bits/stdc++.h>
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
using namespace std;
typedef long long LL;
typedef pair<LL, int> pli;
typedef pair<int, int> pii;
typedef pair<LL, LL> pll;
typedef map<char, int> mci;
typedef map<string, int> msi;
template<class T>
void read(T &res) {
  int f = 1; res = 0;
  char c = getchar();
  while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
  while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); }
  res *= f;
}
const int N = 5100;
int n, m, S;
int val[N], in[N], cost[N];
LL now[N], dp[N][N];
vector<int> ve[N];
void dfs(int u) {
  for(int i = S; i >= 0; --i) {
    if(i >= cost[u]) dp[u][i] = dp[u][i-cost[u]] + val[u];
    else dp[u][i] = -1e18;
  }
  for(int v : ve[u]) {
    for(int i = 0; i <= S; ++i) dp[v][i] = dp[u][i];
    dfs(v);
    for(int i = 0; i <= S; ++i) dp[u][i] = max(dp[u][i], dp[v][i]);
  }
}
int main() {
  int u, v;
  read(n); read(S); read(m);
  for(int i = 1; i <= n; ++i) read(val[i]);
  for(int i = 1; i <= n; ++i) read(cost[i]);
  for(int i = 0; i < m; ++i) {
    read(u); read(v);
    ve[v].push_back(u);
    in[u]++;
  }
  for(int i = 1; i <= n; ++i) {
    if(in[i]) continue;
    ve[0].push_back(i);
  }
  dfs(0);
  LL ans = 0;
  for(int i = 0; i <= S; ++i) ans = max(ans, dp[0][i]);
  printf("%lld\n", ans);
  return 0;
}

L 金牌厨师HiLin与HJGG

做法:题意就是有一个大矩阵,要求选一个最小的m,使得m*m矩阵中所有数字之和大于等于k,用到二位前缀和。

代码

#include<bits/stdc++.h>
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
using namespace std;
typedef long long LL;
typedef pair<LL, int> pli;
typedef pair<int, int> pii;
typedef pair<LL, LL> pll;
typedef map<char, int> mci;
typedef map<string, int> msi;
template<class T>
void read(T &res) {
  int f = 1; res = 0;
  char c = getchar();
  while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
  while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); }
  res *= f;
}
const int N = 2003;
int a[N][N];
LL sum[N][N];
int n, k;
int solve(int x, int y, int nn) {
  x--; y--;
  if(sum[x+nn][y+nn] - sum[x][y+nn] - sum[x+nn][y] + sum[x][y] >= k) return 1;
  return 0;
}
int main() {
  read(n); read(k);
  //二维前缀和预处理
  for(int i = 1; i <= n; ++i) {
    for(int j = 1; j <= n; ++j) {
      read(a[i][j]);
      sum[i][j] = a[i][j] + sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1];
    }
  }
  //暴力枚举每个m,加剪枝
  LL ans = n;
  for(int i = 1; i <= n; ++i) {
    for(int j = 1; j <= n; ++j) {
      for(int nn = ans; nn >= 1 && nn <= n-i+1 && nn <= n-j+1; --nn) {
        if(solve(i, j, nn)) {
          ans = nn;
        } else break;
      }
    }
  }
  if(sum[n][n] < k) puts("I'm a Gold Chef!");
  else printf("%lld\n", ans);
  return 0;
}

发布了28 篇原创文章 · 获赞 14 · 访问量 2959

猜你喜欢

转载自blog.csdn.net/qq_43408978/article/details/103751223
今日推荐