2017 JUST Programming Contest 2.0 题解

 

题目链接

 

A - On The Way to Lucky Plaza

首先,$n>m$或$k>m$或$k>n$就无解。

设$p = \frac{A}{B}$,$ans = C_{n - 1}^{k - 1}{\left( {\frac{A}{B}} \right)^{k}}{\left( {\frac{B-A}{B}} \right)^{n - k}} = \frac{{\left( {n - 1} \right)! \times {A^k} \times {{\left( {B - A} \right)}^{n - k}}}}{{\left( {k - 1} \right)! \times \left( {n - k} \right)! \times {B^n}}}$。令分子为$p$,分母为$q$,最终的答案为$p$*($q$的逆元)。

#include <bits/stdc++.h>
using namespace std;

const long long mod = 1e9 + 7;
const int maxn = 2e5 + 10;
long long f[maxn];

long long m, n, k;
char s[maxn];

long long qpow(long long a, long long b) {
  long long res = 1LL;
  a = a % mod;
  while(b) {
    if(b & 1) res = (res * a) % mod;
    b = b / 2;
    a = (a * a) % mod;
  }
  return res;
}

long long extend_gcd(long long a,long long b,long long &x,long long &y)
{
  if(a==0&&b==0) return -1;//无最大公约数
  if(b==0){x=1;y=0;return a;}
  long long d=extend_gcd(b,a%b,y,x);
  y-=a/b*x;
  return d;
}
//*********求逆元素*******************
//ax = 1(mod n)
long long mod_reverse(long long a,long long n)
{
  long long x,y;
  long long d=extend_gcd(a,n,x,y);
  if(d==1) return (x%n+n)%n;
  else return -1;
}

void init() {
  f[0] = 1LL;
  for(long long i = 1; i <= 100000; i ++) {
    f[i] = (f[i - 1] * i) % mod;
  }
}

int main() {
  init();
  cin >> m >> n >> k >> s;
  if(n > m || k > m || k > n) {
    printf("0\n");
    return 0;
  }
  if(s[0] == '1' && n == k) {
    printf("1\n");
    return 0;
  }
  if(s[0] == '1') {
    printf("0\n");
    return 0;
  }
  if(s[0] == '0' && s[2] == '0' && s[3] == '0' && s[4] == '0') {
    printf("0\n");
    return 0;
  }
  
  long long A = 0;
  long long B = 1000LL;
  for(int i = 2; i <= 4; i ++) {
    A = A * 10LL + s[i] - '0';
  }
  
  long long p, q;
  
  p = f[n - 1] * qpow(A, k) % mod;
  p = p * qpow(B - A, n - k) % mod;
  
  q = f[k - 1] * f[n - k] % mod;
  q = q * qpow(B, n) % mod;
  
  long long x = p * mod_reverse(q, mod) % mod;
  printf("%lld\n", x);
  return 0;
}

 

B - So You Think You Can Count?

设$dp[i]$表示以$i$为结尾的方案数,每个位置最多往前扫$10$位。

#include <bits/stdc++.h>
using namespace std;

const long long mod = 1e9 + 7;
const int maxn = 1e5 + 10;
char s[maxn];
int n;
long long dp[maxn];

long long DP(int x) {
  if(x < 0) return 1LL;
  return dp[x];
}

int main() {
  scanf("%d", &n);
  scanf("%s", s);
  int len = strlen(s);
  dp[0] = 1LL;
  for(int i = 1; i < len; i ++) {
    int tmp[20];
    for(int j = 0; j <= 9; j ++) {
      tmp[j] = 0;
    }
    for(int pre = i; pre >= 0; pre --) {
      if(tmp[s[pre] - '0']) break;
      tmp[s[pre] - '0'] = 1;
      dp[i] = (dp[i] + DP(pre - 1)) % mod;
    }
  }
  printf("%lld\n", dp[len - 1]);
  return 0;
}

 

C - MRT Map

最短路,数据有点水,没把spfa卡住。

#include <bits/stdc++.h>
using namespace std;

const int maxn = 2e5 + 10;

int S, T, n, m;
char name[maxn][25];
int h[maxn], nx[maxn], to[maxn], c[maxn], sz;
int t1[30], t2[30];

int cost(int x, int y) {
  memset(t1, 0, sizeof t1);
  memset(t2, 0, sizeof t2);
  
  for(int i = 0; name[x][i]; i ++){
    if(name[x][i] >= 'a' && name[x][i] <= 'z') {
      t1[name[x][i] - 'a'] ++;
    }
    if(name[x][i] >= 'A' && name[x][i] <= 'Z') {
      t1[name[x][i] - 'A'] ++;
    }
  }
  
  for(int i = 0; name[y][i]; i ++){
    if(name[y][i] >= 'a' && name[y][i] <= 'z') {
      t2[name[y][i] - 'a'] ++;
    }
    if(name[y][i] >= 'A' && name[y][i] <= 'Z') {
      t2[name[y][i] - 'A'] ++;
    }
  }
  
  int num = 0;
  for(int i = 0; i < 26; i ++) {
    if(t1[i] && t2[i]) num ++;
  }
  return num;
}

void add(int x, int y, int z) {
  to[sz] = y;
  c[sz] = z;
  nx[sz] = h[x];
  h[x] = sz++;
}

int dis[maxn], f[maxn];

void spfa() {
  for(int i = 1 ;i <= n; i ++) {
    f[i] = 0;
    dis[i] = 0x7FFFFFFF;
  }
  queue<int> Q;
  Q.push(S);
  f[S] = 1;
  dis[S] = 0;
  while(!Q.empty()) {
    int top = Q.front();
    Q.pop();
    f[top] = 0;
    for(int i = h[top]; i != -1; i = nx[i]) {
      if(dis[top] + c[i] < dis[to[i]]) {
        dis[to[i]] = dis[top] + c[i];
        if(f[to[i]] == 0) {
          f[to[i]] = 1;
          Q.push(to[i]);
        }
      }
    }
  }
}

int main() {
  scanf("%d%d", &n, &m);
  for(int i = 1; i <= n; i ++) {
    scanf("%s", name[i]);
    h[i] = -1;
  }
  for(int i = 1; i <= m; i ++) {
    int u, v;
    scanf("%d%d", &u, &v);
    add(u, v, cost(u, v));
    add(v, u, cost(u, v));
  }
  scanf("%d%d", &S, &T);
  spfa();
  printf("%d\n", dis[T]);
  return 0;
}

 

D - Husam's Bug

模拟。

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e6 + 10;
char s[maxn];

int main() {
  int T;
  scanf("%d", &T);
  while(T --) {
    scanf("%s", s);
    
    int num1=0, num2=0, num3=0;
    for(int i = 0; s[i];i ++) {
      if(s[i]>='a'&&s[i]<='z') num1++;
      else if(s[i]>='A'&&s[i]<='Z') num1++;
      else if(s[i]>='0'&&s[i]<='9') num2++;
      else if(s[i] =='!' || s[i] =='?'||s[i] == '@') {
        num3++;
      }
    }
    if(num1 < 4) {
      printf("The last character must be a letter.\n");
      continue;
    }
    if(num2 < 4) {
      printf("The last character must be a digit.\n");
      continue;
    }
    if(num3 < 2) {
      printf("The last character must be a symbol.\n");
      continue;
    }
    printf("The last character can be any type.\n");
  }
  return 0;
}

 

E - Abdalrahman Ali Bugs

由于验证的复杂度只有$O(26)$,因此可以枚举答案。

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e5 + 10;
int n, m;
char s[maxn];
long long f[maxn];

int main() {
  scanf("%s", s);
  for(int i = 0; s[i]; i ++) {
    f[s[i] - 'a'] ++;
  }
  long long ans = -1;
  long long mn = -1;
  for(long long i = 2; i <= 300000; i ++) {
    long long tmp = 0;
    for(int j = 0; j < 26; j ++) {
      tmp = tmp + (f[j] % i) * f[j];
    }
    if(mn == -1 || tmp < mn) {
      mn = tmp;
      ans = i;
    }
  }
  printf("%lld\n", ans);
  return 0;
}

 

F - Certifications

二分查找。

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e5 + 10;
int n, m;
int a[maxn];

int main() {
  scanf("%d", &n);
  for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
  sort(a + 1, a + 1 + n);
  scanf("%d", &m);
  while(m --) {
    int x;
    scanf("%d", &x);
    int L = 1, R = n, pos = -1;
    while(L <= R) {
      int mid = (L + R) / 2;
      if(a[mid] >= x) pos = mid, R = mid - 1;
      else L = mid + 1;
    }
    if(pos == -1) printf("Dr. Samer cannot take any offer :(.\n");
    else printf("%d\n", a[pos]);
  }
  return 0;
}

 

G - In the Chairman's office

模拟。

#include <bits/stdc++.h>
using namespace std;

int main() {
  int n, m;
  cin>> n>>m;
  if(m % n == 0) printf("YES\n");
  else printf("NO\n");
  return 0;
}

 

H - Give Me This Pizza

这题为单调栈经典问题,但是由于数值范围只有$50$,因此可以枚举数值。

#include <bits/stdc++.h>
using namespace std;

const int maxn = 2e5 + 10;
int n, m;
int a[maxn];
int b[maxn];
int num[maxn];

int main() {
  scanf("%d", &n);
  for(int i = 1; i <= n; i ++) {
    scanf("%d", &a[i]);
  }
  for(int i = 0; i<= 100; i ++) num[i] = 200000;
  for(int j = n; j>=1; j--) {
    b[j] = 200000;
    for(int k = 50; k >= a[j] + 1; k--){
      if(num[k] < b[j]) b[j] = num[k];
    }
    num[a[j]] = j;
    if(b[j] != 200000) b[j] = a[b[j]];
    else b[j] = -1;
  }
  for(int i =1 ;i <= n; i ++) {
    printf("%d ", b[i]);
  }
  return 0;
}

 

I - Husam and the Broken Present 1

对主对角线开根号来求解。

#include <bits/stdc++.h>
using namespace std;

int main() {
  int n;
  cin>> n;
  int x;
  for(int i = 1; i <= n; i ++) {
    for(int j = 1; j <= n; j++){
      cin>>x;
      if(i == j){
        int num = sqrt(1.0 * x);
        while(num * num > x) num--;
        while(num*num<x)num++;
        printf("%d ", num);
      }
      
    }
  }
  return 0;
}

 

J - Husam and the Broken Present 2

先删除被包含的那些数组,剩下的可以进行状压$dp$来决策放置顺序。$dp[st][v]$表示有$st$状态里面的子数组已经放置好了,最后放的是$v$的最小花费,和TSP是一样的问题。

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1000;
vector<int> vec[maxn], t[maxn];
int cost[20][20];

int n;
int dp[70000][17];

int han(vector<int>& a, vector<int>& b) {
  // a 是否在 b 中
  if(b.size() < a.size()) return 0;
  for(int i = 0; i < b.size(); i ++) {
    int L = i, R = i + a.size() - 1;
    if(R >= b.size()) break;
    int fail = 0;
    for(int j = 0; j < a.size(); j ++) {
      if(a[j] != b[L + j]) fail = 1;
    }
    if(fail == 0) return 1;
  }
  return 0;
}

int cal(int x, int y) {
  // x 后面 接 y
  int res = 0;
  for(int i = 0; i < t[x].size(); i ++) {
    if(t[x].size() - i > t[y].size()) continue;
    int fail = 0;
    for(int j = i; j < t[x].size(); j ++) {
      if(t[x][j] != t[y][j - i]) fail = 1;
    }
    //printf("!!! %d, %d\n", i, fail);
    if(fail == 0) {
      res = t[x].size() - i;
      break;
    }
    
  }
  return t[y].size() - res;
}

bool cmp(const vector<int> &a, const vector<int> &b) {
  return a.size() > b.size();
}

int main() {
  scanf("%d", &n);
  for(int i = 0; i < n; i ++) {
    int x;
    scanf("%d", &x);
    while(x--){
      int p;
      scanf("%d", &p);
      vec[i].push_back(p);
    }
  }
  sort(vec, vec + n, cmp);
  int sz = 0;
  t[sz++] = vec[0];
  for(int i = 1; i < n; i ++) {
    int fail = 0;
    for(int j = 0; j < sz; j ++) {
      if(han(vec[i], t[j])) {
        fail = 1;
        break;
      }
    }
    if(fail) continue;
    t[sz ++] = vec[i];
  }
  
  n = sz;
  
  /*
  for(int i = 0; i < n; i ++) {
    for(int j = 0; j < t[i].size(); j ++) {
      cout << t[i][j] << " ";
    }
    cout << endl;
  }
   */
  
  for(int i = 0; i < n; i ++) {
    for(int j = 0; j < n; j ++) {
      if(i == j) continue;
      cost[i][j] = cal(i, j);
    }
  }
  
  for(int st = 0; st < (1 << n); st ++) {
    for(int i = 0; i < n; i ++) {
      dp[st][i] = 200000;
    }
  }
  for(int i = 0; i < n; i ++) {
    dp[1 << i][i] = t[i].size();
  }
  
  for(int st = 1; st < (1 << n); st ++) {
    for(int pre = 0; pre < n; pre ++) {
      if(((1 << pre) & st) == 0) continue;
      for(int now = 0; now < n; now ++) {
        if((1 << now) & st) continue;
        dp[st | (1 << now)][now] = min(dp[st | (1 << now)][now], dp[st][pre] + cost[pre][now]);
      }
    }
  }
  
  int ans = dp[(1 << n) - 1][0];
  for(int i = 0; i < n; i ++) {
    ans = min(ans, dp[(1 << n) - 1][i]);
  }
  printf("%d\n", ans);
  
  return 0;
}

/*
 3
 2 1 2
 4 3 4 5 6
 3 2 3 4
 
 */

 

posted @ 2018-02-19 16:45  Fighting_Heart  阅读(577)  评论(0编辑  收藏  举报