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

 

D - zzq的离散数学教室1

$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$ 的素因子个数就不多。

类似的题目推荐:ZOJ 4008

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

 

E - 小木乃伊到我家

最短路。一开始忘记优先队列是大的排在前面了,果然是智力有缺陷。

#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 - 连续区间的最大公约数

以每一个位置 $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  |
  
 */

 

K - zzq的离散数学教室2

这题看上去好像和 2017 ICPC 南宁 M 题一样,都是求最长反链长度。最长反链长度 = 最小链覆盖数,原题在 BZOJ 1143。两种做法:第一种做法传递闭包搞,第二种做法网络流上对流量做一些改造。第二种能适应这题的数据规模。

 

L - 仓鼠养殖计划

队友写的,我题意都不知道。

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

 

posted @ 2018-04-14 21:32  Fighting_Heart  阅读(570)  评论(0编辑  收藏  举报