1. 程式人生 > >2018年東北農業大學春季校賽 題解

2018年東北農業大學春季校賽 題解

題目連結

寫在前面:從都到尾做了一下這場比賽,似乎好題都是原題,水題都是他們學校自己出的。原題在抄過來的過程中,很多題目的題面、資料範圍都出了問題,還有題目資料很水。建議以後這樣的比賽不要掛到外面來了,不然別人會罵你們學校不負責任的... ...

吐槽:

1. 牛客網題面上輸入順序寫錯了,明明是按 k,a,b 的順序輸入,題面上缺寫了以 a,b,k 的順序輸入。

2. 資料很水,我用精確度非常低的方法能水過去

3. 建議將程式碼提交到原題上進行測評:HDU 4498

精確第很低的方法牛客網上水過:

#include <bits/stdc++.h>
using namespace std;
 
const double eps = 1e-8;
const int maxn = 1e5 + 10;
const int INF = 0x7FFFFFFF;
 
int n;
double k[maxn], a[maxn], b[maxn];
 
double f(double x) {
  double res = 100.0;
    for(int i = 1; i <= n; i ++) {
      res = min(res, 1.0 * k[i] * (x - a[i]) * (x - a[i]) + 1.0 * b[i]);
    }
    return res;
}
 
double dis(double x1, double y1, double x2, double y2) {
    return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
 
double cal(double L, double R) {
  return dis(L, f(L), R, f(R));
}
 
double work(double L, double R) {
//  printf("[%.2f, %.2f]\n", L, R);
    double mid = (L + R) / 2;
    if(R - L > 0.005) {
        return work(L, mid) + work(mid, R);
    }
    double s0 = cal(L, mid);
    double s1 = cal(mid, R);
    double s2 = cal(L, R);
    if(fabs(s0 + s1 - s2) < eps) return s0 + s1;
    return work(L, mid) + work(mid, R);
}
 
int main() {
 
//  freopen("test.in", "r", stdin);
 
     
      scanf("%d", &n);
        for(int i = 1; i <= n; i ++) {
          scanf("%lf%lf%lf", &k[i], &a[i], &b[i]);
        }
        printf("%.2f\n", work(0.0, 100.0));
     
     
    return 0;
}

正解:求出所有拋物線之間的交點,相鄰兩個交點之間必然有一條曲線需要統計到答案中去,設拋物線方程為 $f(x)$,那麼 $[L, R]$ 的曲線長度為 $\int _{ L }^{ R }{ \sqrt { { f^{ ' }\left( x \right)  }^{ 2 }+1 } dx } $。利用自適應 simpson 積分公式加上分治即可。

#include <bits/stdc++.h>
using namespace std;
 
const double eps = 1e-8;
const int maxn = 1e5 + 10;
const int INF = 0x7FFFFFFF;
 
int n;
double k[maxn], a[maxn], b[maxn];
vector<double> vec;
 
double f(double x) {
    double res = 100.0;
    for(int i = 1; i <= n; i ++) {
        res = min(res, k[i] * (x - a[i]) * (x - a[i]) + b[i]);
    }
    return res;
}
 
void h(int x, int y) {
    double ta = (k[x]) - (k[y]);
    double tb = (-k[x] * a[x] * 2.0) - (-k[y] * a[y] * 2.0);
    double tc = (k[x] * a[x] * a[x] + b[x]) - (k[y] * a[y] * a[y] + b[y]);
 
    double delta = tb * tb - 4.0 * ta * tc;
    if(delta < 0) return;
 
    double x1 = (-tb - sqrt(delta)) / (2.0 * ta);
    double x2 = (-tb + sqrt(delta)) / (2.0 * ta);
 
    if(x1 >= 0.0 && x1 <= 100.0) vec.push_back(x1);
    if(x2 >= 0.0 && x2 <= 100.0) vec.push_back(x2);
//  printf("%f %f\n", x1, x2);
}
 
double G(double x, int idx) {
    double tmp = 2.0 * k[idx] * x - 2 * a[idx] * k[idx];
    return sqrt(tmp * tmp + 1.0);
}
 
double cal(double L, double R, int idx) {
    double res = 0.0;
    res = (R - L) / 6.0 * (G(L, idx) + 4.0 * G((L + R) / 2.0, idx) + G(R, idx));
    return res;
}
 
double work(double L, double R, int idx) {
    double mid = (L + R)  /2;
    double s0 = cal(L, mid, idx);
    double s1 = cal(mid, R, idx);
    double s2 = cal(L, R, idx);
    if(fabs(s0 + s1 - s2) < eps) return s0 + s1;
    return work(L, mid, idx) + work(mid, R, idx);
}
 
int main() {
 
 
        scanf("%d", &n);
        for(int i = 1; i <= n; i ++) {
            scanf("%lf%lf%lf", &k[i], &a[i], &b[i]);
        }
        b[0] = 100.0;
        n ++;
 
        vec.clear();
        vec.push_back(0.0);
        vec.push_back(100.0);
        for(int i = 0; i < n; i ++) {
            for(int j = i + 1; j < n; j ++) {
                h(i, j);
            }
        }
        sort(vec.begin(), vec.end());
 
        for(int i = 0; i < vec.size(); i ++) {
    //      printf("%d : %f\n", i, vec[i]);
        }
 
        double ans = 0.0;
        for(int i = 1; i < vec.size(); i ++) {
            double L = vec[i - 1];
            double R = vec[i];
            double mid = (L + R) / 2;
 
            int idx = 0;
            double Min = 100.0;
            for(int j = 0; j < n; j ++) {
                if(k[j] * (a[j] - mid) * (a[j] - mid) + b[j] < Min) {
                    Min = k[j] * (a[j] - mid) * (a[j] - mid) + b[j];
                    idx = j;
                }
            }
    //      printf("[%lf, %lf], %d ", L, R, idx);
    //      printf(" len : %lf\n", work(L, R, idx));
            ans = ans + work(L, R, idx);
        }
        printf("%.2f\n", ans);
     
    return 0;
}

手算一下前幾項就能找到規律了,答案是一個數的平方,那個數有規律。

#include <bits/stdc++.h>
using namespace std;
 
long long a[100010];
 
void init() {
  a[3] = 5;
  long long cha = 8;
  for(int i = 5; i <= 10000; i = i + 2) {
    a[i] = a[i-2] +cha;
    cha = cha + 4;
  }
}
 
int main() {
  init();
  int T;
  int n;
  scanf("%d", &T);
  while(T--) {
    scanf("%d", &n);
    printf("%lld\n", a[n]*a[n]);
  }
  return 0;
}

吐槽:牛客網資料有點水,建議提交到原題 POJ 3728 進行測評

從 $u$ 走到 $v$ 的最大收益分三種情況:

1. $[u, lca(u,v)]$ 進行買賣

2. $[lca(u,v), v]$ 進行買賣

3. $[u, lca(u,v)]$ 進行買,$[lca(u,v), v]$ 進行賣

倍增預處理從 $i$ 節點,往上走 $2^j$ 步的最大值,最小值,最大收益,倒著走下來的最大收益四個值就可以進行詢問了。

#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <cstring>
using namespace std;
 
const int maxn = 1e5 + 10;
const int INF = 0x7FFFFFFF;
 
int n,  w[maxn];
int h[maxn], nx[maxn], to[maxn];
int sz;
 
int f[maxn][20];
int Min[maxn][20];
int Max[maxn][20];
int Up[maxn][20];
int Down[maxn][20];
int dep[maxn], vis[maxn];
 
void add(int x, int y) {
    to[sz] = y;
    nx[sz] = h[x];
    h[x] = sz ++;
}
 
void dfs(int x,int fa) {
    vis[x] = 1;
 
    if(fa == -1) dep[x] = 1;
    else dep[x] = dep[fa] + 1;
 
    f[x][0] = x;
    f[x][1] = fa;
    for(int i = 2; i < 18; i ++) {
        f[x][i] = -1;
        if((1 << i) <= dep[x]) {
            f[x][i] = f[f[f[x][i - 1]][1]][i - 1];
        }
    }
 
    Min[x][0] = w[x];
    Max[x][0] = w[x];
    Up[x][0] = 0;
    Down[x][0] = 0;
    for(int i = 1; i < 18; i ++) {
        if((1 << i) > dep[x]) continue;
        Min[x][i] = min(Min[x][i - 1], Min[f[f[x][i - 1]][1]][i - 1]);
        Max[x][i] = max(Max[x][i - 1], Max[f[f[x][i - 1]][1]][i - 1]);
        Up[x][i] = max(max(Up[x][i - 1], Up[f[f[x][i - 1]][1]][i - 1]),
                Max[x][i - 1] - Min[f[f[x][i - 1]][1]][i - 1]);
        Down[x][i] = max(max(Down[x][i - 1], Down[f[f[x][i - 1]][1]][i - 1]),
                Max[f[f[x][i - 1]][1]][i - 1] - Min[x][i - 1]);
    }
 
    for(int i = h[x]; i != -1; i = nx[i]) {
        if(vis[to[i]]) continue;
        dfs(to[i], x);
    }
}
 
int LCA(int x, int y) {
    if(dep[x] < dep[y]) {
        swap(x, y);
    }
 
    int pre = 17;
    while(dep[x] != dep[y]) {
        for(int j = pre; j >= 0; j --) {
            if(f[x][j] == -1) continue;
            if(dep[f[x][j]] < dep[y]) continue;
            x = f[x][j];
            pre = j;
            break;
        }
    }
 
    if(x == y) return x;
 
    pre = 17;
    while(f[x][1] != f[y][1]) {
        for(int j = pre; j >= 0; j --) {
            if(f[x][j] == f[y][j]) continue;
            x = f[x][j];
            y = f[y][j];
            pre = j;
            break;
        }
    }
 
    x = f[x][1];
    return x;
}
 
int GetMax(int x, int y) {
    int res = w[x];
    int pre = 17;
    while(x != y) {
        for(int j = pre; j >= 0; j --) {
            if(f[x][j] == -1) continue;
            if(dep[f[x][j]] < dep[y]) continue;
            res = max(res, Max[x][j]);
            x = f[x][j];
            pre = j;
            break;
        }
    }
    return res;
}
 
int GetMin(int x, int y) {
    int res = w[x];
    int pre = 17;
    while(x != y) {
        for(int j = pre; j >= 0; j --) {
            if(f[x][j] == -1) continue;
            if(dep[f[x][j]] < dep[y]) continue;
            res = min(res, Min[x][j]);
            x = f[x][j];
            pre = j;
            break;
        }
    }
    return res;
}
 
int GetMaxUp(int x, int y) {
    if(x == y) return 0;
    int res = 0;
    for(int j = 17; j >= 0; j --) {
        if(f[x][j] == -1) continue;
        if(dep[f[x][j]] < dep[y]) continue;
        if(dep[f[x][j]] == dep[y]) return Up[x][j];
        res = max(Up[x][j], GetMaxUp(f[f[x][j]][1] ,y));
        res = max(res, GetMax(x, f[x][j]) - GetMin(f[f[x][j]][1], y));
        break;
    }
    return res;
}
 
int GetMaxDown(int x, int y) {
    if(x == y) return 0;
    int res = 0;
    for(int j = 17; j >= 0; j --) {
        if(f[x][j] == -1) continue;
        if(dep[f[x][j]] < dep[y]) continue;
        if(dep[f[x][j]] == dep[y]) return Down[x][j];
        res = max(Down[x][j], GetMaxDown(f[f[x][j]][1] ,y));
        res = max(res, GetMax(f[f[x][j]][1], y) - GetMin(x, f[x][j]));
        break;
    }
    return res;
}
 
int main() {
 
//  freopen("test.in", "r", stdin);
 
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++) {
        scanf("%d", &w[i]);
        h[i] = -1;
    }
    for(int i = 1; i < n; i ++) {
        int x, y;
        scanf("%d%d", &x, &y);
        add(x, y);
        add(y, x);
    }
    dfs(1, -1);
 
/*
    for(int i = 1; i <= n; i ++) {
        printf("Node : %d\n", i);
        for(int j = 0; j < 30; j ++) {
            printf("%d  to : %d, Min : %d, Max : %d, Up : %d, Down : %d\n", j, f[i][j], Min[i][j], Max[i][j],
                    Up[i][j], Down[i][j]);
        }
    }
*/
 
    int Q;
    scanf("%d", &Q);
    while(Q --) {
        int x, y, lca;
        scanf("%d%d", &x, &y);
        /* x -> y */
        lca = LCA(x, y);
    //  cout << x << " " << y << ", lca : " << lca << endl;
        int ans = 0;
        ans = max(ans, GetMax(y, lca) -  GetMin(x, lca));
        ans = max(ans, GetMaxDown(x, lca));
        ans = max(ans, GetMaxUp(y, lca));
        printf("%d\n", ans);
    }
 
    return 0;
}

BFS 一下就好了。

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

int T, n, m;
char s[600][600];
int f[600][600];
int sx, sy, ex, ey;

int dir[4][2] = {
  {-1, 0},
  {1, 0},
  {0, -1},
  {0, 1},
};

int out(int x, int y) {
  if(x < 0 || x >= n) return 1;
  if(y < 0 || y >= m) return 1;
  return 0;
}

int main() {
  scanf("%d", &T);
  while(T--) {
    memset(f, 0, sizeof f);
    scanf("%d%d",&n,&m);
    for(int i = 0; i < n; i ++) {
      scanf("%s", s[i]);
      for(int j = 0; j < m; j ++) {
        if(s[i][j] == 's') sx = i, sy = j;
        if(s[i][j] == 't') ex = i, ey = j;
      }
    }
    
    
    queue<pair<int, int> > q;
    q.push(make_pair(sx, sy));
    f[sx][sy] = 1;
    
    while(!q.empty()) {
      pair<int, int> tp = q.front();
      q.pop();
     // cout << tp.first << " " << tp.second << endl;
      for(int i = 0; i < 4; i ++) {
        int nx = tp.first + dir[i][0];
        int ny = tp.second + dir[i][1];
        if(out(nx,ny)) continue;
        if(s[nx][ny] == 'x') continue;
        if(f[nx][ny]) continue;
        q.push(make_pair(nx, ny));
        f[nx][ny] = 1;
      }
      
    }
    
    if(f[ex][ey]) printf("YES\n");
    else printf("NO\n");
    
  }
  return 0;
}

看 $[1,n]$ 這些數素因子分解後,2 的個數和 5 的個數的較小值,顯然 5 比 2 少,只要統計 5 的個數就可以了。

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

int T;
char s[100010];

int find(int n){
  int count= 0;
  while(n > 0){
    count += n / 5;
    n = n / 5;
  }
  return count;
}

int main() {
  scanf("%d",&T);
  while(T--) {
    long long n;
    scanf("%lld",&n);
    printf("%lld\n", find(n));
  }
  return 0;
}

兩邊個數差值越少乘積越大。

#include <bits/stdc++.h>
using namespace std;
 
int main() {
  int T;
  long long n;
  scanf("%d", &T);
  while(T--) {
    scanf("%lld", &n);
    if(n == 0 || n == 1) {
      printf("%d\n", 0);
    } else {
      long long x = n/2;
      long long y = n-n/2;
      printf("%lld\n", x* y);
    }
  }
  return 0;
}

考慮每個人對答案做出的貢獻,每個人對答案都貢獻都是一樣的。

假設 $n$ 個人總共打了 $s$ 分,平均值 $ave = \frac { s }{ n } $,我們只要讓一個人打平均分,然後去看剩下的 $n-1$ 個人打 $s - ave$ 分有幾種方案,這個可以 $dp$ 得到。

#include <bits/stdc++.h>
using namespace std;
 
const int mod = 1000000007;
const int maxn = 1e5 + 10;
const int INF = 0x7FFFFFFF;
 
int T;
int n, m;
 
int f[70][13000];
int sum[13000];
 
int GetPos(int x) {
    if(x < 0) return 0;
    return sum[x];
}
 
int Get(int L, int R) {
    //  cout << L << " " << R << endl;
    return (GetPos(R) - GetPos(L - 1) + mod) % mod;
}
 
void init() {
    memset(f, 0, sizeof f);
    f[0][0] = 1;
    for(int i = 0; i <= 12000; i ++) {
        sum[i] = 1;
    }
    for(int i = 1; i <= n; i ++) {
        for(int j = 0; j <= i * m; j ++) {
            f[i][j] = Get(j - min(m, j), j);
 
            /*
                 for(int k = 0; k <= min(m, j); k ++) {
                 f[i][j] = (f[i][j] + f[i - 1][j - k]) % mod;
                 }
             */
 
        }
        sum[0] = f[i][0];
        for(int j = 1; j <= 12000; j ++) {
            sum[j] = (sum[j - 1] + f[i][j]) % mod;
        }
    }
}
 
int main() {
    //freopen("test.in", "r", stdin);
    scanf("%d", &T);
    while(T --) {
        scanf("%d%d", &n, &m);
        init();
        int ans = 0;
        for(int s = 0; s <= n * m; s ++) {
            if(s % n) continue;
            int ave = s / n;
            long long tmp = 1LL * f[n - 1][s - ave] * n % mod;
            ans = (ans + tmp) % mod;
        }
        printf("%d\n", ans);
    }
    return 0;
}

主要注意安全區域是一個連通塊即可,並非一個格子,有可能是一群格子。

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

const int maxn = 1010;
const int INF = 0x7FFFFFFF;
char s[maxn][maxn];
int n, k;

int sx, sy;
int ex, ey;

int dis[maxn][maxn][2];
int f[maxn][maxn][2];

int dir[4][2] = {
  {1, 0},
  {-1, 0},
  {0, 1},
  {0, -1}
};

int out(int x, int y) {
  if(x < 0 || x >= n) return 1;
  if(y < 0 || y >= n) return 1;
  return 0;
}

int main() {
  int T;
  scanf("%d", &T);
  while(T--) {
    scanf("%d%d", &n, &k);
    for(int i = 0; i < n; i ++) {
      scanf("%s", s[i]);
    }
    
    if(n > 100) while(1) {}
    int sum = 0;
    sx = sy = ex = ey = -1;
    for(int i = 0; i < n; i ++) {
      for(int j = 0; j < n; j ++) {
        if(s[i][j] == 'S') sx = i, sy = j;
        if(s[i][j] == 'X') sum++, ex = i, ey = j;
        dis[i][j][0] = dis[i][j][1] = INF;
      }
    }
    
  //  if(sum != 1) while(1) {}
    
    if(sx == -1 || sy == -1 || ex == -1 || ey == -1){
      while(1) {}
    }
    
    queue<int> qx;
    queue<int> qy;
    queue<int> qc;
    
    qx.push(sx);
    qy.push(sy);
    qc.push(0);
    
    memset(f, 0, sizeof f);
    dis[sx][sy][0] = 0;
    f[sx][sy][0] = 1;
    
    while(!qx.empty()) {
      
      int nx = qx.front();
      int ny = qy.front();
      int nc = qc.front();
      
      qx.pop();
      qy.pop();
      qc.pop();
      
     // cout << nx<<" " << ny << " " <<nc<<endl;
      
      f[nx][ny][nc] = 0;
      
      for(int i = 0; i < 4; i ++) {
        int tx = nx + dir[i][0];
        int ty = ny + dir[i][1];
        int tc = nc;
        
        if(out(tx, ty)) continue;
        if(s[tx][ty] == 'O') continue;
        
        if(s[tx][ty] == 'C') tc = 1;
        
       // cout << tx<<" " << ty << " " <<tc<<endl;
        
        int cost;
        if(nc == 0) cost = 2;
        else cost = 1;
        
        if(dis[nx][ny][nc] + cost < dis[tx][ty][tc]) {
          dis[tx][ty][tc] = dis[nx][ny][nc] + cost;
          if(f[tx][ty][tc] == 0) {
            f[tx][ty][tc] = 1;
            qx.push(tx);
            qy.push(ty);
            qc.push(tc);

          }
        }
        
      }
    }
    
    int ans = INF;
    for(int i = 0; i < n; i ++) {
      for(int j = 0; j < n; j ++) {
        if(s[i][j] == 'X') {
          ans = min(ans, dis[i][j][0]);
          ans = min(ans, dis[i][j][1]);
        }
      }
    }
    
    if(ans > k) {
      printf("NO\n");
    } else {
      printf("YES\n");
      printf("%d\n", ans);
    }
    
  }
  return 0;
}


/*
1
 10 100
 ..........
 ..........
 .......X..
 ..........
 ..........
 ..........
 ..........
 ..S.......
 ..........
 ..........
 
 */

經典的 01 分數規劃。首先有一個單調性,比例越小越可能構造出來,比例越大越不可能構造出來,外面只要驗證大於等於 $x$ 的比例能不能構造出來,如果可以,答案會更大,否則答案會更小,因此可以二分 $x$,然後進行驗證。

驗證 $\frac { \sum { b }  }{ \sum { a }  } \ge x $ 是否可行,等價於驗證 $\sum { b } -x\sum { a } \ge 0$ 是否可行。另 ${ c }_{ i } = { b }_{ i }-x*{ a }_{ i }$,只要取最大的 $k$ 個 $c$,看 $sum$ 是否大於等於 0 即可。

#include <bits/stdc++.h>
using namespace std;
 
const int maxn = 1e5 + 10;
const int INF = 0x7FFFFFFF;
 
int T, n, k;
double a[maxn], b[maxn], c[maxn];
 
int check(double x) {
    for(int i = 1; i <= n; i ++) {
      c[i] = b[i] - x * a[i];
    }
    sort(c + 1, c + 1 + n);
    double sum = 0.0;
    for(int i = n; i >= n - k + 1; i --) {
      sum = sum + c[i];
    }
    if(sum >= 0) return 1;
    return 0;
}
 
int main() {
   
//  freopen("test.in", "r", stdin);
 
    scanf("%d", &T);
    while(T --) {
        scanf("%d%d", &n, &k);
        for(int i = 1; i <= n; i ++) {
          scanf("%lf%lf", &a[i], &b[i]);
        }
        double L = 0, R = 1e18, ans;
        for(int it = 1; it <= 100; it ++) {
            double mid = (L + R) / 2;
            if(check(mid)) {
              ans = mid;
                L = mid;
            } else {
              R = mid;
            }
        }
        printf("%.2f\n", ans);
    }
    return 0;
}

吐槽:牛客網上資料錯了,我多次和出題人說,他不信。建議提交到原題進行測評:NYOJ 304

如果資料沒有錯,下面這個程式碼怎麼會超時?感覺出(chao)題人很逗啊... ...

#include <bits/stdc++.h>
using namespace std;
  
const long long limit = 1e9;
const long long INF = limit * limit;
struct X {
  int id;
  long long d, w;
}s[1010];
int n;
int id;
  
bool cmp(const X&a, const X&b) {
  return a.d < b.d;
}
  
long long dp[1010][1010][2];
  
long long sum[1010];
  
long long cal(int x1, int y1, int x2, int y2) {
  return sum[y1] - sum[x1 - 1] - (sum[y2] - sum[x2 - 1]);
}
  
int main() {
  while(~scanf("%d%d", &n, &id)) {
    for(int i = 1; i <= n; i ++) {
      scanf("%lld%lld", &s[i].d, &s[i].w);
      sum[i] = sum[i - 1] + s[i].w;
      s[i].id = i;
        if(i > 1 && s[i].d < s[i-1].d) while(1) {}
    }
     
  }
  return 0;
}

正解:

可以觀察到如果他從起點出發關了某盞燈,那麼途徑的燈都會被關掉,也就是從起點往兩邊跑來跑去關燈的過程,很明顯是個區間 dp,記錄一下關完某個區間的燈,在左端點還有右端點的最小耗電量即可。

#include <bits/stdc++.h>
using namespace std;
 
const long long limit = 1e9;
const long long INF = limit * limit;
struct X {
  int id;
  long long d, w;
}s[1010];
int n;
int id;
 
bool cmp(const X&a, const X&b) {
  return a.d < b.d;
}
 
long long dp[1010][1010][2];
 
long long sum[1010];
 
long long cal(int x1, int y1, int x2, int y2) {
  return sum[y1] - sum[x1 - 1] - (sum[y2] - sum[x2 - 1]);
}
 
int main() {
  while(~scanf("%d%d", &n, &id)) {
    for(int i = 1; i <= n; i ++) {
      scanf("%lld%lld", &s[i].d, &s[i].w);
      sum[i] = sum[i - 1] + s[i].w;
      s[i].id = i;
    }
     
    for(int i = 1; i <= n; i ++) {
      for(int j = i; j <= n; j ++) {
        dp[i][j][0] = INF;
        dp[i][j][1] = INF;
      }
    }
     
    dp[id][id][0] = dp[id][id][1] = 0;
     
    for(int len = 2; len <= n; len ++) {
      for(int L = 1; L <= n; L ++) {
        int R = L + len - 1;
        if(R > n) break;
         
        // cal [L][R][0]
         
          // [L, R - 1][0]
        if(dp[L][R - 1][0] != INF)
        dp[L][R][0] = min(dp[L][R][0],
                          dp[L][R - 1][0]
                          + (s[R].d - s[L].d) * cal(1, n, L, R - 1)
                          + (s[R].d - s[L].d) * cal(1, n, L, R));
          // [L, R - 1][1]
        if(dp[L][R - 1][1] != INF)
        dp[L][R][0] = min(dp[L][R][0],
                          dp[L][R - 1][1]
                          + (s[R].d - s[R - 1].d) * cal(1, n, L, R - 1)
                          + (s[R].d - s[L].d) * cal(1, n, L, R));
          // [L + 1, R][0]
        if(dp[L + 1][R][0] != INF)
        dp[L][R][0] = min(dp[L][R][0],
                          dp[L + 1][R][0]
                          + (s[L + 1].d - s[L].d) * cal(1, n, L + 1, R));
          // [L + 1, R][1]
        if(dp[L + 1][R][1] != INF)
        dp[L][R][0] = min(dp[L][R][0],
                          dp[L + 1][R][1]
                          + (s[R].d - s[L].d) * cal(1, n, L + 1, R));
         
        // cal [L][R][1]
         
          // [L, R - 1][0]
        if(dp[L][R - 1][0] != INF)
        dp[L][R][1] = min(dp[L][R][1],
                          dp[L][R - 1][0]
                          + (s[R].d - s[L].d) * cal(1, n, L, R - 1));
          // [L, R - 1][1]
        if(dp[L][R - 1][1] != INF)
        dp[L][R][1] = min(dp[L][R][1],
                          dp[L][R - 1][1]
                          + (s[R].d - s[R - 1].d) * cal(1, n, L, R - 1));
          // [L + 1, R][0]
        if(dp[L + 1][R][0] != INF)
        dp[L][R][1] = min(dp[L][R][1],
                          dp[L + 1][R][0]
                          + (s[L + 1].d - s[L].d) * cal(1, n, L + 1, R)
                          + (s[R].d - s[L].d) * cal(1, n, L, R));
          // [L + 1, R][1]
        if(dp[L + 1][R][1] != INF)
        dp[L][R][1] = min(dp[L][R][1],
                          dp[L + 1][R][1]
                          + (s[R].d - s[L].d) * cal(1, n, L + 1, R)
                          + (s[R].d - s[L].d) * cal(1, n, L, R));
      }
    }
    printf("%lld\n", min(dp[1][n][0], dp[1][n][1]));
  }
  return 0;
}

去尋找 $f_i=0$, $f_{i+1}=1$的除 0 之外的最小 $i$,找到了這個就找到了迴圈節。

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

unsigned long long f[5000];

unsigned long long a, b;
unsigned long long c;

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

int main() {
  int T;
  scanf("%d", &T);
  while(T--) {
    cin >> a >> b >> c;
    f[0] = 0;
    f[1] = 1;
    unsigned long long limit;
    for(int i = 2; ; i ++) {
      f[i] = (f[i-1]+ f[i-2]) % c;
      
      if(f[i] == 1 && f[i-1] == 0) {
        limit = i;
        break;
      }
    }
    
    //[0, limit - 2]
   
    cout << f[qpow(a, b, limit - 1)] << endl;
    
  }
  return 0;
}


/*

 
 3
 1 1 2
 2 3 1000
 32122142412412142 124124124412124 123
 
 */

吐槽:開啟題目,看到萌值沒有資料範圍,問了一下出(chao)題人,說是在 $[1, 10^5]$,然後我開始寫,寫完提交,返回錯誤,看了好久程式碼,看不出毛病,然後我就在想可能優秀的出(chao)題人告訴我的資料範圍是騙我的,因此我擴大到了 $10^6$,提交返回正確。CNMLGB ?後來出題人在題面上 update 了資料範圍:$[1,1000000000]$,再一次騙我?我開到 $10^6$ 是怎麼過的?

題解:經典的權值線段樹,直接線上段樹上選擇往右走還是往左走就可以了。

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

const int maxn = 1e6+10;
int T;

int s[maxn * 4];

char op[20];
int n, m;
int ans;

void build(int l, int r, int rt) {
  s[rt] = 0;
  if(l == r) return;
  int mid = (l+r)/2;
  build(l, mid, 2*rt);
  build(mid+1, r, 2*rt+1);
}

void update(int pos, int val, int l, int r, int rt) {
  if(l == r) {
    s[rt] += val;
    return;
  }
  int mid = (l+r)/2;
  if(pos <= mid) update(pos, val, l, mid, 2 * rt);
  else update(pos, val, mid+1, r, 2*rt+1);
  s[rt] = s[2*rt]+s[2*rt+1];
}

void query(int k, int l, int r, int rt) {
  if(l == r) {
    ans = l;
    return;
  }
  int mid = (l+r)/2;
  if(s[2*rt+1] >= k) query(k,mid+1,r,2*rt+1);
  else query(k - s[2*rt+1],l,mid,2*rt);
}

int main() {
  scanf("%d",&T);
  while(T--) {
    scanf("%d%d",&n,&m);
    build(0,1e6,1);
    for(int i = 1; i <= n; i ++) {
      int x;
      scanf("%d",&x);
      if(x > 1e6) while(1) {}
      update(x,1,0,1e6,1);
    }
    
    while(m--) {
      scanf("%s", op);
      int x;
      scanf("%d", &x);
      if(op[0] == 'q') {
        query(x,0,1e6,1);
        printf("%d\n", ans);
      } else if(op[0] == 'i') {
        if(x > 1e6) while(1) {}
        update(x, 1, 0, 1e6, 1);
      } else {
        if(x > 1e6) while(1) {}
        update(x, -1, 0, 1e6, 1);
      }
    }
    
  }
  return 0;
}

水題。

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

int T;
char s[100010];

int main() {
  scanf("%d",&T);
  while(T--) {
    scanf("%s",s);
    int ans = 0;
    for(int i = 0; s[i];i++){
      if(s[i] == '7') ans++;
    }
    cout << ans <<endl;
  }
  return 0;
}

相關推薦

2018東北農業大學春季 題解

【題目連結】 寫在前面:從都到尾做了一下這場比賽,似乎好題都是原題,水題都是他們學校自己出的。原題在抄過來的過程中,很多題目的題面、資料範圍都出了問題,還有題目資料很水。建議以後這樣的比賽不要掛到外面來了,不然別人會罵你們學校不負責任的... ... 吐槽: 1. 牛客網題面上輸入順序寫

2018東北農業大學春季 K-why的數列(斐波那契數列迴圈節)

連結:https://www.nowcoder.com/acm/contest/93/K來源:牛客網題目描述 wyh學長特別喜歡斐波那契數列,F(0)=0,F(1)=1,F(n)=F(n-1)+F(n

2018東北農業大學春季 K wyh的數列

連結:點選開啟連結題目描述 wyh學長特別喜歡斐波那契數列,F(0)=0,F(1)=1,F(n)=F(n-1)+F(n-2)(n>=2) 一天他突發奇想,想求F(a^b)%c 輸入描述:輸入第一行一個整數T(1<=T<=100),代表測試組數 接下來

2018東北農業大學春季 B wyh的矩陣【規律】

題目連結 思路 先加入 中間的那行 和中間的那列 再減去 最中間那個數 因為它 加了兩次 然後逐行往下加 會發現是一個三角形 然後下面是一個對稱的三角形 注意一下 不要反覆加 就可以了

動態規劃--dp--2018東北農業大學春季J

來源:牛客網 我國現在能源消耗非常嚴重,現在政府有這樣一個工作,每天早上都需要把一些路燈關掉,但是他們想讓在關閉的過程中所消耗的能源是最少的,負責路燈關閉的工作人員以1m/s的速度進行行走,假設關閉路燈的時候不需要花費任何的時間,請你編寫一個程式,計算在給定路燈位置和每個

2018東北農業大學春季

【題目】 A wyh的曲線 10/51 未通過 學一下求曲線長度? B wyh的矩陣 461/1355 通過 規律題方便打表的先打表再推 C wyh的商機 12/31 未通過 離線LCA? D wyh的迷宮

2018東北農業大學春季 B題題解

#include<iostream> #include<algorithm> using namespace std; int main() { long long t,n;cin>>t; long long sum=0;

2018東北農業大學春季H題wyh的吃雞

題目描述 最近吃雞遊戲非常火,你們wyh學長也在玩這款遊戲,這款遊戲有一個非常重要的過程,就是要跑到安全區內,否則就會中毒持續消耗血量,我們這個問題簡化如下假設地圖為n*n的一個圖,圖中有且僅有一塊X的聯通快代表安全區域,有一個起點S代表縮圈的時候的起點,圖中C代表的是車(保

2018東北農業大學春季:L-wyh的天鵝(Treap)

題意:插入元素,刪除元素,查詢第K大。題解:Treap。#include <bits/stdc++.h> using namespace std; #define Lc (o -> Ch[0]) #define Rc (o -> Ch[1]) #de

2018東北農業大學春季 K、wyh的數列

題意:  斐波拉契數列f[0]=0、f[1]=1 , f[n]=f[n-1]+f[n-2](n>=2);求f[a^b]%c.(a、b<=2^64、2<=c<=1000)***因為

2018東北農業大學春季 B

連結:https://www.nowcoder.com/acm/contest/93/B來源:牛客網時間限制:C/C++ 1秒,其他語言2秒空間限制:C/C++ 262144K,其他語言524288K 64bit IO Format: %lld題目描述 給你一個n*n矩陣,

2018東北農業大學春季D wyh的迷宮

給你一個n*m的迷宮,這個迷宮中有以下幾個標識: s代表起點 t代表終點 x代表障礙物 .代表空地 現在你們涵哥想知道能不能從起點走到終點不碰到障礙物(只能上下左右進行移動,並且不能移動到已經移動過的點)。 輸入描述:輸入第一行一個整數T(1<=T<=1

2018東北農業大學春季 B wyh的矩陣 【規律】

連結:https://www.nowcoder.com/acm/contest/93/B #include<bits/stdc++.h> using namespace std; #define ll long long int main() { int

2018東北農業大學春季 L-wyh 【線段樹】

題目描述  你們wyh學長小時候住在河邊,因為周圍的生態環境非常好,所以經常會有天鵝浮在湖面上,每隻天鵝都長得不一樣,它們偶爾排成一排,偶爾分散開,偶爾也會去其他河畔,wyh學長為了統計它們的個數,編了一個程式賦予它們一個“萌”值,但是這些天鵝很不聽話,一會兒會從別的地方游

2018東北農業大學春季 H why的吃雞

連結:點選開啟連結題目描述 最近吃雞遊戲非常火,你們wyh學長也在玩這款遊戲,這款遊戲有一個非常重要的過程,就是要跑到安全區內,否則就會中毒持續消耗血量,我們這個問題簡化如下 假設地圖為n*n的一個圖,圖中有且僅有一塊X的聯通快代表安全區域,有一個起點S代表縮圈的時

2018東北農業大學春季-A:wyh的曲線(Simpson)

時間限制:C/C++ 1秒,其他語言2秒空間限制:C/C++ 262144K,其他語言524288K64bit IO Format: %lld題目描述給你三組數列,分別為現在給你一個式子:然後我們可以將

2018東北農業大學春季——why的數字

題目描述 wyh學長十分鐘愛數字‘7’,他想知道每一個數字中有多少個數字‘7’ 輸入描述: 輸入第一行一個整數T(1<=T<=10) 接下來有T組測試資料,對於每組測試資料,輸

東北農業大學春季——wyh的數字(輸出各位上數字)

輸入描述: 輸入第一行一個整數T(1<=T<=10) 接下來有T組測試資料,對於每組測試資料,輸入一個整數n(1<=n<=10000000000) 輸出描述: 對於每組測試資料

2018東北】UPC-7226 Memory Banks(模擬儲存)

題目描述 We have purchased 60 different types of memory banks, typed as 0 to 59, A bank of type i has 2i

2018山東大學acmB

YangFan is a wayward boy who likes to count in his own way.The number he writes may be 0 or 1 for each digit, and the last non-zero digit may be 2, and the