1. 程式人生 > >2018年長沙理工大學第十三屆程式設計競賽 題解

2018年長沙理工大學第十三屆程式設計競賽 題解

題目連結

A - LL

簡單題。

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

int T;
char s[2000];

int main() {
  while(gets(s)) {
    int len = strlen(s);
    for(int i = 0; s[i]; i ++) {
      if(s[i] >= 'A' && s[i] <= 'Z') {
        s[i] = s[i] - 'A' + 'a';
      }
    }
    if(len != 8 || (strcmp("lovelive", s) != 0)) {
      printf("no\n");
      
    }else {
      printf("yes\n");
    }
  }
  return 0;
}

B - 奇怪的加法

高精度加法一下,不要進位就好了。

#include <bits/stdc++.h>
using namespace std;
 
char s[20];
char t[20];
char ans[20];
int limit;
 
int main() {
  while(~scanf("%s%s",s,t)) {
    limit = 20;
    int lens = strlen(s);
    int lent = strlen(t);
     
    for(int i = 0; i < lens / 2; i ++) {
      swap(s[i], s[lens - i - 1]);
    }
     
    for(int i = 0; i < lent / 2; i ++) {
      swap(t[i], t[lent - i - 1]);
    }
     
    //printf("%s %s\n", s, t);
     
    for(int i = lens; i < limit; i ++) {
      s[i] = '0';
    }
     
    for(int i = lent; i < limit; i ++) {
      t[i] = '0';
    }
     
    for(int i = 0; i < limit; i ++) {
      int nums = s[i] - '0';
      int numt = t[i] - '0';
      ans[i] = (char)('0' + ((nums + numt) % 10));
    }
     
    int pos = 0;
     
    for(int i = 19; i >= 0; i --) {
      if(ans[i] != '0') {
        pos = i;
        break;
      }
    }
     
    for(int i = pos; i >= 0; i --) {
      printf("%c", ans[i]);
    }
    printf("\n");
     
  }
  return 0;
}

C - 取手機

總共排列方案有 ${ C }_{ a+b }^{ a }$ 種,第 $k$ 位是 b 手機的方案有 ${ C }_{ a+b-1 }^{ a }$ 種,因此概率為 $\frac { { C }_{ a+b-1 }^{ a } }{ { C }_{ a+b }^{ a } } =\frac { b }{ a+b } $。

#include <bits/stdc++.h>
using namespace std;
 
int T;
 
int main() {
   
  scanf("%d", &T);
  while(T --) {
    long long a, b, k;
    scanf("%lld%lld%lld", &a,&b,&k);
    printf("%.3f\n", 1.0*b/(a+b));
  }
  return 0;
}

$b=a\times prime$,因此列舉 $prime$,看有多少 $(a,b)$ 滿足即可,算一下發現方案數是 $\left\lfloor \frac { R }{ prime }  \right\rfloor -L+1$。

這種做法的複雜度為 $O(P \times Q)$。其中 $P$ 為素數個數,$Q$ 為詢問次數。

#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 1e6 + 10;
int p[N], a[N], b[N];
int ans[N],tt=0;
int f[N];
int t, u;
 
void init(){
    t = 0, u = 0;
    for (int i = 2;i < N;i++) {
        if (a[i] == 0) p[t++] = i, a[i] = i;
        for (int j = 0;j < t && i * p[j] < N;j++) {
            a[i*p[j]] = p[j];
            if (i % p[j] == 0) {           
                break;
            }
        }
    }
     
    //printf("%d\n", t);
}
 
int main(){
    init();
    int L, R;
    while(~scanf("%d%d", &L, &R)) {
        int ans = 0;
        for(int i = 0; i < t; i ++) {
            if(L * p[i] > R) break;
            ans = ans + R / p[i] - L + 1;
        }
        printf("%d\n", ans);
    }
    return 0;
}

這題詢問出到 $10^5$ 次也可以搞。

假設有一堆滿足條件的二元組 $(a,b)$,對於一次詢問 $(L, R)$,我們需要尋找有多少個二元組滿足 $a$ 和 $b$ 均在 $[L,R]$ 內,這個就是很經典的問題了,離線很容易操作,要求線上的話就主席樹。這裡我們可以處理出所有滿足條件的二元組,不會很多,因為 $b$ 的素因子個數就不多。

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int p[N], a[N], b[N];
int ans[N],tt=0;
int f[N];

struct point{
	int l,r,id;
}x[N];

int low(int x) {
	return x&(-x);
}

void add(int x) {
	for (int i = x;i<N;i+=low(i)) {
		f[i]++;
	}
}

int sum(int x) {
	int res = 0;
	for (int i = x;i > 0;i-=low(i)) {
		res+=f[i];
	}
	return res;
}

void init(){
	int t = 0, u = 0;
	for (int i = 2;i < N;i++) {
		if (a[i] == 0) p[t++] = i, a[i] = i;
		for (int j = 0;j < t && i * p[j] < N;j++) {
			a[i*p[j]] = p[j];
			if (i % p[j] == 0) {
				break;
			}
		}
		int o = 0;
		for (int j = i;j > 1;j /= a[j]) {
			b[o++] = a[j];
		}
		sort(b,b+o);

		o = unique(b,b+o) - b;
		for (int j = 0;j<o;j++) {
			add(i/b[j]);
			//cout << "debug " << i / b[j] << endl;
		}

		for (;u<tt && x[u].r <= i;u++) {
			if (x[u].l >= x[u].r) ans[x[u].id] = 0;
			else {
				ans[x[u].id] = sum(x[u].r) - sum(x[u].l - 1);
			}
		}
		if (u==tt) break;
	}
}

bool cmp(point a,point b) {
	return a.r < b.r;
}

int main(){
#ifdef ZHOUZHENTAO
	freopen("test.in", "r", stdin);
#endif
	while (~scanf("%d%d",&x[tt].l,&x[tt].r)){
		x[tt].id = tt;
		tt ++;
	}
	sort(x,x+tt,cmp);
	init();
	for (int i = 0;i < tt;i++) {
		printf("%d\n",ans[i]);
	}

	return 0;
}

最短路。一開始忘記優先佇列是大的排在前面了,果然是智力有缺陷。

#include <bits/stdc++.h>
using namespace std;
  
const int maxn = 4e5 + 10;
 long long INF = 1e9;
int T;
int n, m;
int sz, h[maxn], nx[maxn], to[maxn];
long long val[maxn];
  
long long dis[maxn];
  
void add(int x, int y, long long z) {
  to[sz] = y;
  val[sz] = z;
  nx[sz] = h[x];
  h[x] = sz ++;
}
  
int main() {
    
  INF = INF * INF;
    
  scanf("%d%d", &n, &m);
  for(int i = 1; i <= n; i ++) {
    h[i] = -1;
    dis[i] = INF;
  }
    
  for(int i = 1; i <= m; i ++) {
    int u, v;
    long long w;
    scanf("%d%d%lld", &u, &v, &w);
    add(u, v, w);
    add(v, u, w);
  }
    
  priority_queue<pair<long long, int> > q;
    
  q.push(make_pair(0, 1));
  dis[1] = 0;
    
  while(!q.empty()) {
    pair<long long, int> pi = q.top();
    q.pop();
      
    if(dis[pi.second] < -pi.first) continue;
      
    for(int i = h[pi.second]; i!=-1;i=nx[i]) {
      if(dis[pi.second] + val[i] < dis[to[i]]) {
        dis[to[i]] = dis[pi.second] + val[i];
        q.push(make_pair(-dis[to[i]], to[i]));
      }
    }
      
  }
    
  if(dis[n] == INF) {
    printf("qwb baka\n");
  } else {
    printf("%lld\n", dis[n]);
  }
    
    
  return 0;
}

F - 箱庭的股市

仔細觀察一下可以發現就是求楊輝三角某一行的字首和。

#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
int m,x,y,p;
int f[N], g[N], inv[N];
 
int main(){
    f[0] = g[0] = f[1] = g[1] = inv[1] = 1;
    for (int i = 2;i<N;i++) {
        f[i] = 1LL * f[i-1] * i % mod;
        inv[i] = 1LL * inv[mod % i] * (mod - mod /i) % mod;
        g[i] = 1LL * g[i-1] * inv[i] % mod;
    }
    while (~scanf("%d%d%d%d",&m,&x,&y,&p)) {
        int ans = 0;
        if (x==1||y==0) {
            printf("%d\n", p);
            continue;
        }
        x = x - 1;
        for (int i = 0;i<= min(y,x);i++) {
            ans = (ans + 1LL * f[x] * g[i] % mod * g[x-i] % mod) % mod;
        }
        ans = 1LL * p * ans % mod;
        printf("%d\n",ans);
    }
}

G - 逃離迷宮

吐槽:題目裡說:“現在你需要花費最少的時間拿到鑰匙然後從迷宮的出口出去”。我一開始理解為首先是要求到鑰匙的時間最少,然後從最少時間的鑰匙那裡挑一個走到出口,結果答案錯誤,後來改成整體最少時間就 AC 了。這個我感覺確實會引起歧義啊。

#include <bits/stdc++.h>
using namespace std;
 
int INF = 10000000;
const int maxn = 550;
int T;
int n, m;
char s[maxn][maxn];
 
int sx, sy;
int ex, ey;
 
int dis[2][maxn][maxn];
 
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;
}
 
void bfs(int flag) {
  queue<int> q;
  if(flag == 0) {
    dis[flag][sx][sy] = 0;
    q.push(sx * m + sy);
  } else {
    dis[flag][ex][ey] = 0;
    q.push(ex * m + ey);
  }
   
  while(!q.empty()) {
    int st = q.front();
    q.pop();
     
    int nx = st / m;
    int ny = st % m;
     
    for(int i = 0; i < 4; i ++) {
      int tx = nx + dir[i][0];
      int ty = ny + dir[i][1];
      if(out(tx, ty)) continue;
      if(s[tx][ty] == '#') continue;
      if(flag == 0 && s[tx][ty] == 'E') continue;
      if(dis[flag][nx][ny] + 1 < dis[flag][tx][ty]) {
        dis[flag][tx][ty] = dis[flag][nx][ny] + 1;
        q.push(tx * m + ty);
      }
    }
  }
}
 
int main() {
  scanf("%d", &T);
  while(T --) {
    scanf("%d%d", &n, &m);
    for(int i = 0; i < n; i ++) {
      scanf("%s", s[i]);
    }
    for(int i = 0; i < n; i ++) {
      for(int j = 0; j < m; j ++) {
        if(s[i][j] == 'P') sx = i, sy = j;
        else if(s[i][j] == 'E') ex = i, ey = j;
        dis[0][i][j] = dis[1][i][j] = INF;
      }
    }
     
    bfs(0);
    bfs(1);
     
    int ans = INF;
    
 
    for(int i = 0; i < n; i ++) {
      for(int j = 0; j < m; j ++) {
        if(s[i][j] != 'K') continue;
        if(dis[0][i][j] == INF) continue;
        if(dis[1][i][j] == INF) continue;
        ans = min(ans, dis[0][i][j] + dis[1][i][j]);
      }
    }
     
    if(ans == INF) {
      printf("No solution\n");
      continue;
    }
     
    printf("%d\n", ans);
  }
  return 0;
}

H - 數學考試

列舉分割線,然後左邊最大值和右邊最大值加一加更新答案。左右兩邊最大值 dp 一下就能算出來了。

#include <bits/stdc++.h>
using namespace std;
 
const int maxn = 2e5 + 10;
long long INF = 1e9;
 
int T, n, k;
long long a[maxn];
long long L[maxn], R[maxn];
 
int main() {
  INF = INF * INF;
   
  scanf("%d", &T);
  while(T --) {
    scanf("%d%d", &n, &k);
    for(int i = 1; i <= n; i ++) {
      scanf("%lld", &a[i]);
    }
     
    long long sum = 0;
    for(int i = 1; i <= k; i ++) {
      sum = sum + a[i];
    }
    L[k] = sum;
    for(int i = k + 1; i <= n; i ++) {
      sum = sum - a[i - k] + a[i];
      L[i] = max(L[i - 1], sum);
    //  cout << sum << endl;
    }
     
    sum = 0;
    for(int i = n; i >= n - k + 1; i --) {
      sum = sum + a[i];
    }
    R[n - k + 1] = sum;
    for(int i = n - k; i >= 1; i --) {
      sum = sum - a[i + k] + a[i];
      R[i] = max(R[i + 1], sum);
    //  cout << sum << endl;
    }
     
    long long ans = L[k] + R[k + 1];
     
    for(int i = k; i + k <= n; i ++) {
      // [, i], [i + 1, i + k]
      ans = max(ans, L[i] + R[i + 1]);
    //  cout << L[i] << " " << R[i + 1] << endl;
    }
     
    printf("%lld\n", ans);
     
     
  }
  return 0;
}

以每一個位置 $i$ 作為區間右端點,左端點從 $[1, i]$ 移動的過程中,區間 gcd 的種類不會超過 $log(n)$ 種,我們可以把這些處理出來,記錄成四元組 $\left( { L }_{ 1 },L_{ 2 },R,g \right) $,表示區間左端點在 $[L_1,L_2]$,右端點在 $R$ 的所有區間,最大公約數均為 $g$。

所有的四元組已經 cover 了所有的子區間。那麼對於每一次的詢問 $(L, R, g)$,我們只需在和這一次詢問擁有相同 $g$ 的四元組中尋找答案,去計算每一個四元組做出的貢獻。

例如詢問為 $(4, 7, 3)$,四元組 $(1, 3, 3, 3)$ 的貢獻為 0,雖然 $g$ 均為 3,但是無相交部分。四元組 $(2, 5, 6, 3)$ 的貢獻為 2。雖然以 6 為結尾的有 4 個區間 $g$ 為 3,但是隻有 2 個在詢問的區間內。

一種效率較高的做法如下:

把詢問離線,詢問中 $g$ 相同的歸為一類,去 gcd 為 $g$ 的四元組中計算答案。也就是按 $g$ 分類來計算。

下面只考慮相同 $g$ 情況下的詢問和四元組之間如何計算答案。

對於一次詢問 $(L, R, g)$,就是求 $R$ 小於等於詢問的 $R$ 的四元組 $[L_1,L_2]$ 和 $[L, R]$ 交集長度之和。每次暴力求的話,複雜度為 $O(n^2)$,事實上可以按 $R$ 排序,然後利用線段樹區間修改、求區間和來搞。 

/*******************************
    Judge Result : AC
 *******************************/
 
#include <bits/stdc++.h>
#define rep(i,j,k) for (int i = j; i <= k; i++)
#define per(i,j,k) for (int i = j; i >= k; i--)
#define loop(i,j,k) for (int i = j;i != -1; i = k[i])
#define lson x << 1, l, mid
#define rson x << 1 | 1, mid + 1, r
#define ff first
#define ss second
#define mp(i,j) make_pair(i,j)
#define pb push_back
#define pii pair<int,LL>
#define in(x) scanf("%d", &x);
using namespace std;
typedef long long LL;
const int low(int x) { return x&-x; }
const double eps = 1e-4;
const int INF = 0x7FFFFFFF;
const int N = 4e5 + 10;
int T, n, m, l, r;
int g[N],d[N];
 
long long s[N], k[N];
 
int gcd(int x, int y) {
    return x%y ? gcd(y, x%y) : y;
}
 
void build(int x,int l,int r) {
    if (l == r) {
        scanf("%d",&g[x]);
        d[r] = g[x];
    }
    else {
        int mid = l + r >> 1;
        build(lson);
        build(rson);
        g[x] = gcd(g[x<<1], g[x<<1|1]);
    }
}
 
int query(int x,int l,int r,int ll,int rr) {
    if (ll<=l && r<=rr) return g[x];
    int mid = l + r>>1;
    if (rr <= mid) return query(lson,ll,rr);
    else if (ll > mid) return query(rson,ll,rr);
    else return gcd(query(lson,ll,rr),query(rson,ll,rr));
}
 
void pushUp(int rt) {
    s[rt] = s[2 * rt] + s[2 * rt + 1];
}
 
void pushDown(int rt, int l, int r) {
    if(k[rt] == 0) return;
    int mid = (l + r) / 2;
    s[2 * rt] += (k[rt] * (mid - l + 1));
    s[2 * rt + 1] += (k[rt] * (r - mid));
    k[2 * rt] += k[rt];
    k[2 * rt + 1] += k[rt];
    k[rt] = 0;
}
 
void update(int L, int R, long long val, int l, int r, int rt) {
    if(L <= l && r <= R) {
        s[rt] += (val * (r - l + 1));
        k[rt] += val;
        return;
    }
    int mid = (l + r) / 2;
    pushDown(rt, l, r);
    if(L <= mid) update(L, R, val, l, mid, 2 * rt);
    if(R > mid) update(L, R, val, mid + 1, r, 2 * rt + 1);
    pushUp(rt);
}
 
long long get(int L, int R, int l, int r, int rt) {
    if(L <= l && r <= R) return s[rt];
    pushDown(rt, l, r);
    int mid = (l + r) / 2;
    long long left = 0, right = 0;
    if(L <= mid) left = get(L, R, l, mid, 2 * rt);
    if(R > mid) right = get(L, R, mid + 1, r, 2 * rt + 1);
    pushUp(rt);
    return left + right;
}
 
struct point{
    int l,r,g, id;
}c[N];
 
struct point2 {
    int l1, l2, r, g;
}h[N];
int szh;
 
long long ans[N];
 
bool cmpc(const point& a, const point& b) {
    if(a.g != b.g) return a.g < b.g;
    return a.r < b.r;
}
 
bool cmph(const point2& a, const point2& b) {
    if(a.g != b.g) return a.g < b.g;
    return a.r < b.r;
}
 
bool cmpid(const point& a, const point& b ) {
    return a.id < b.id;
}
 
int main() {
#ifdef ZHOUZHENTAO
    freopen("test.in", "r", stdin);
#endif
 
    scanf("%d", &T);
    int cas = 0;
    while (T--) {
        scanf("%d", &n);
        build(1, 1, n);
        scanf("%d", &m);
        printf("Case #%d:\n", ++cas);
        for (int i = 0;i< m ;i++) {
            scanf("%d%d", &c[i].l, &c[i].r);
            c[i].g = query(1, 1, n, c[i].l, c[i].r);
            c[i].id = i;
        }
 
        szh = 0;
        stack<pii> a, b;
        rep(i, 1, n) {
            a.push(mp(d[i], 1));
            while (!a.empty()) b.push(mp(gcd(a.top().ff, d[i]), a.top().ss)), a.pop();
            while (!b.empty()) {
                pii q = b.top();    b.pop();
                if (!a.empty() && a.top().ff == q.ff) q.ss += a.top().ss, a.pop();
                a.push(q);
            }
 
            int L = i;
            while (!a.empty()) {
                pii q = a.top(); a.pop();
                int LL = L - q.second + 1;
                h[szh].l1 = LL;
                h[szh].l2 = L;
                h[szh].r = i;
                h[szh].g = q.first;
                szh ++;
                L = LL - 1;
                b.push(q);
            }
            while (!b.empty()) {
                a.push(b.top()); b.pop();
            }
        }
 
        sort(c, c + m, cmpc);
        sort(h, h + szh, cmph);
        /* 
                for(int i = 0; i < szh; i ++) {
                cout << h[i].l1 << " " << h[i].l2 << " " << h[i].r << " " << h[i].g << endl;
                }
 
                for(int i = 0; i < m; i ++) {
                cout << c[i].l << " " << c[i].r << " " << c[i].g << endl;
                }
         */
        for(int i = 0; i < m; i ++) {
            ans[i] = 0;
        }
        for(int i = 0, j = 0; i < szh; i = j + 1, j = i) {
            while(j < szh - 1 && h[j].g == h[j + 1].g) j ++;
            // [i, j]
 
            int L = 0, R = m - 1, pos1 = -1, pos2 = -1;
            while(L <= R) {
                int mid = (L + R) / 2;
                if(c[mid].g < h[i].g) L = mid + 1;
                else if(c[mid].g > h[i].g) R = mid - 1;
                else pos1 = mid, R = mid - 1;
            }
 
            if(pos1 == -1) continue;
 
            L = 0, R = m - 1;
            while(L <= R) {
                int mid = (L + R) / 2;
                if(c[mid].g < h[i].g) L = mid + 1;
                else if(c[mid].g > h[i].g) R = mid - 1;
                else pos2 = mid, L = mid + 1;
            }
 
            //[pos1, pos2]
            /*
                 printf("[%d, %d]  [%d, %d]\n", i, j, pos1, pos2);
             */
            int y = i;
            for(int k = pos1; k <= pos2; k ++) {
                while(y <= j && h[y].r <= c[k].r) {
                    update(h[y].l1, h[y].l2, 1LL, 1, n, 1);
                    y ++;
                }
                ans[c[k].id] = get(c[k].l, c[k].r, 1, n, 1);
            }
 
            for(int k = i; k < y; k ++) {
                update(h[k].l1, h[k].l2, -1LL, 1, n, 1);
            }
 
        }
 
        sort(c, c + m, cmpid);
        for(int i = 0; i < m; i ++) {
            printf("%d ", c[i].g);
            printf("%lld\n", ans[i]);
        }
 
    }
    return 0;
}

J - 杯子

這題和這題完全一樣。

#include <bits/stdc++.h>
using namespace std;
 
typedef long long LL;
LL p = 1e9 + 7;
 
const int maxn = 3e6 + 10;
LL f[maxn];
 
//******************************
//返回d=gcd(a,b);和對應於等式ax+by=d中的x,y
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;
}
 
LL C(LL n, LL m) {
  long long A = f[n];
  long long B = f[n - m] * f[m] % p;
  long long C = mod_reverse(B, p);
  return A * C % p;
}
 
LL work(LL n, LL m) {
  if(n == m) return 1;
  return (C(n * 2 - m - 1, n - m)
          - C(n * 2 - m - 1, n - m - 1)
          + p) % p;
}
 
int main() {
  f[0] = 1;
  for(long long i = 1; i < maxn; i ++) {
    f[i] = (f[i - 1] * i) % p;
  }
  int T;
  scanf("%d", &T);
  while(T --) {
    LL n, m, k;
    scanf("%lld%lld%lld", &n, &m, &k);
    if(m > n || m < k) {
      printf("0\n");
      continue;
    }
    LL A = work(m, k);
    LL B = work(n + k + 1 - m, k + 1);
    LL ans = A * B % p;
    printf("%lld\n", ans);
  }
  return 0;
}
/*
  
 A:
 ---+-----------------------------------
 m\k|   1    2    3    4    5    6    7
 ---+-----------------------------------
 1  |   1
 2  |   1    1
 3  |   2    2    1
 4  |   5    5    3    1
 5  |  14   14    9    4    1
 6  |  42   42   28   14    5    1
 7  | 132  132   90   48   20    6    1
  
 B:
 n = 1
 ---+-----------------------------------
 m\k|   1    2    3    4    5    6    7
 ---+-----------------------------------
 1  |   1
 2  |
 3  |
 4  |
 5  |
 6  |
 7  |
  
 n = 2
 ---+-----------------------------------
 m\k|   1    2    3    4    5    6    7
 ---+-----------------------------------
 1  |   2
 2  |   1    1
 3  |
 4  |
 5  |
 6  |
 7  |
  
 n = 3
 ---+-----------------------------------
 m\k|   1    2    3    4    5    6    7
 ---+-----------------------------------
 1  |   5
 2  |   2    3
 3  |   1    1    1
 4  |
 5  |
 6  |
 7  |
  
 n = 4
 ---+-----------------------------------
 m\k|   1    2    3    4    5    6    7
 ---+-----------------------------------
 1  |   14
 2  |   5    9
 3  |   2    3    4
 4  |   1    1    1   1
 5  |
 6  |
 7  |
  
 n = 5
 ---+-----------------------------------
 m\k|   1    2    3    4    5    6    7
 ---+-----------------------------------
 1  |   42
 2  |   14  28
 3  |   5    9   14
 4  |   2    3    4    5
 5  |   1    1    1    1    1
 6  |
 7  |
  
 */

這題看上去好像和 2017 ICPC 南寧 M 題一樣,都是求最長反鏈長度。最長反鏈長度 = 最小鏈覆蓋數,原題在 BZOJ 1143。兩種做法:第一種做法傳遞閉包搞,第二種做法網路流上對流量做一些改造。第二種能適應這題的資料規模。

隊友寫的,我題意都不知道。

#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
int T,a,b,n, c[N];
 
bool check() {
    for (int i = 1;i<=n;i++) {
        while (c[i]) {
            if (a+b==0) break;
            if (a==0) {
                c[i] = max(0,c[i]-2);
                b--;
            }
            else if (b==0) {
                c[i]--; a--;
            }
            else if (c[i]>1) {
                c[i]-=2; b--;
            }
            else {
                c[i]--; a--;
            }
        }
        if (c[i]) return false;
    }
    return true;
}
 
int main(){
    for (scanf("%d",&T);T--;) {
        scanf("%d%d%d",&a,&b,&n);
        for (int i = 1;i<=n;i++) {
            scanf("%d",&c[i]);
        }
        puts(check()?"Yes":"No");
    }
    return 0;
}

相關推薦

2018長沙理工大學十三程式設計競賽 題解

【題目連結】 A - LL 簡單題。 #include <bits/stdc++.h> using namespace std; int T; char s[2000]; int main() { while(gets(s)) { int len

2018長沙理工大學十三程序設計競賽 題解

pair UC www. queue 一行 priority char s tps PC 【題目鏈接】 A - LL 簡單題。 #include <bits/stdc++.h> using namespace std; int T;

2018長沙理工大學十三程序設計競賽 G 逃離迷宮

-h solution algorithm 如果 space 重復 都是 程序 empty 題目描述 給你一個n*m的圖,地圖上‘.‘代表可以走的地方,而‘#‘代表陷阱不能走,‘P‘代表人物位置,‘K‘代表鑰匙,‘E‘代表出口。人物一個,鑰匙有多個,(‘K‘的數量&

POJ 2287 Tian Ji -- The Horse Racing&&浙江科技學院十三程式設計競賽1006 田忌賽馬後傳(貪心)

思路:如果田忌最慢的比齊王最慢的快,或者田忌最快的比齊王最快的快,那麼就比,否則讓田忌最慢的和齊王最快的比。 #include<map> #include<queue> #in

哈爾濱理工大學程式設計競賽決賽(網路賽-低年級組)

給出一個序列,你的任務是求序列中 (a[j]-a[i])/(j-i)【1<=i<j<=n】的最大值輸入描述:本題包含多組輸入,每組輸入第一行一個數字n,表示序列的長度。 然後接下來一行輸入n個數,表示原先序列的樣子。 資料範圍: 3<=n<=200000 -1000000000&

哈爾濱理工大學程式設計競賽決賽 A 所有情況的和

題目描述 在acimo星球, tabris 是一名勇敢的屠龍勇士,在上綠島屠龍前決定挑選N種裝備武裝自己,現在每種裝備有兩個,但每種裝備tabris必須選擇拿一個,不能多也不能少。 每件裝備有自己的屬性值,能給tabris屬性加成。 對於不同種類的裝備之間

哈爾濱理工大學程式設計競賽初賽(低年級組)

今天是Tabris和mengxiang000來到幼兒園的第9天。 為了慶祝這美好的一天,老師組織同學們做遊戲,拿來了好多骰子。 遊戲規則: 1)兩個人每人輪流擲骰子,操控同一個小人在一個有向的地圖上走,骰子的點數是幾,這個小人就向前走幾格。 2) 地圖只有一條路,路上有起點、終點和傳送陣。傳送陣會只能

哈爾濱理工大學程式設計競賽初賽(高年級組)F 苦逼的單身狗【DP】

時間限制:C/C++ 1秒,其他語言2秒 空間限制:C/C++ 32768K,其他語言65536K 64bit IO Format: %lld 題目描述 雙11又到了,小Z依然只是一隻單身狗,對

"尚學堂杯"哈爾濱理工大學程式設計競賽 C.Collection Game【遞推】

Collection Game Time Limit: 1000 MS Memory Limit: 128000 K Total Submit: 41(21 users) Total Accept

福州大學十三程式設計競賽_重現

 Problem C 平行四邊形數 Accept: 71    Submit: 345 Time Limit: 2000 mSec    Memory Limit : 32768 KB  Problem Description 在一個平面內給定n個點,任意三個點不在同

【哈爾濱理工大學程式設計競賽初賽(高年級組)】 A B C D F G H I

A 凌波微步 時間限制:C/C++ 1秒,其他語言2秒 空間限制:C/C++ 32768K,其他語言65536K 64bit IO Format: %lld 題目描述 小Z的體型實在是太胖了,每次和小D一起出門都跟不上小D的腳步,這讓小Z很氣餒

哈爾濱理工大學程式設計競賽決賽(網路賽-高年級組)-D:數圈圈(數位DP)

時間限制:C/C++ 1秒,其他語言2秒空間限制:C/C++ 32768K,其他語言65536K64bit IO Format: %lld 題目描述 tabris有一個習慣,無聊的時候就會

哈爾濱理工大學程式設計競賽決賽 D 數圈圈

時間限制:C/C++ 1秒,其他語言2秒 空間限制:C/C++ 32768K,其他語言65536K 64bit IO Format: %lld 題目描述 tabris有一個習慣,無聊的時候就會數圈圈,無論數字還是字母。 現在t

哈爾濱理工大學程式設計競賽初賽(高年級組)F.苦逼單身狗(滑動視窗 or DP or 二分)

思路:滑動視窗 or DP or 二分。滑動視窗:#include <bits/stdc++.h> using namespace std; const int MAXN = 100005;

哈爾濱理工大學程式設計競賽決賽(網路賽-高年級組)B 幸運大獎【DP】

時間限制:C/C++ 1秒,其他語言2秒 空間限制:C/C++ 32768K,其他語言65536K 64bit IO Format: %lld 題目描述 tabris實在是太窮了,為了發財,ta

哈爾濱理工大學程式設計競賽初賽(高年級組)F-苦逼的單身狗

連結:https://www.nowcoder.com/acm/contest/27/F來源:牛客網題目描述 雙11又到了,小Z依然只是一隻單身狗,對此他是如此的苦惱又無可奈何。 為了在這一天脫

哈爾濱理工大學程式設計競賽決賽(網路賽-高年級組)B題幸運大獎

幸運大獎 時間限制:C/C++ 1秒,其他語言2秒 空間限制:C/C++ 32768K,其他語言65536K 64bit IO Format: %lld 題目描述 tabris實在是太窮了,為了發財,tabris去買了一張彩票,幸運地中了特別獎。 特別獎是這樣的,不會直接給

哈爾濱理工大學程式設計競賽(G.Great Atm)

Description An old story said the evil dragon wasn’t evil at all, only bewitched, and now that the riddles were solved it was prov

哈爾濱理工大學程式設計競賽初賽(高年級組)I 旅行【列舉+spfa】

時間限制:C/C++ 2秒,其他語言4秒 空間限制:C/C++ 32768K,其他語言65536K 64bit IO Format: %lld 題目描述 小z放假了,準備到RRR城市旅行,其中這個城市有N個旅遊景點。小z時間有限,只能在三個旅行景點進行遊

哈爾濱理工大學程式設計競賽初賽(高年級組)H 佈置會場【斐波那契】

時間限制:C/C++ 1秒,其他語言2秒 空間限制:C/C++ 32768K,其他語言65536K 64bit IO Format: %lld 題目描述 小d接到了一個佈置會場的任務。 他需要