小练习 Div3(1324,1328)& 周末练习(3.15&3.22)

补题
DIV3(1324A-E)

1324A - Yet Another Tetris Problem
挂了一次是因为没有break
1324B - Yet Another Palindrome Problem
找出长度为3的回文串即可

#include<iostream>
#include<string>
#include<unordered_set>
#include<vector>
#include<queue>
#include<set>
#include<cmath>
#include<iomanip>
#include<string>
#include<string.h>
#include<map>
#define INF 0x3f3f3f3f;
const int maxn = 5 * 1e3 + 5;
using namespace std;
int t, n,a[maxn];
struct P {
 int c1, c2;
}book[maxn][maxn];
void ini() {
 for (int i = 1;i <= n;i++)
  for (int j = 1;j <= n;j++)
   book[i][j].c1 = book[i][j].c2 = 0;
}
int main() {
 ios::sync_with_stdio(false);
 cin.tie(false);
 cin >> t;
 while (t--) {
  ini();
  bool f = 0;
  cin >> n;
  for (int i = 1;i <= n;i++) {
   cin >> a[i];
  }
  for (int i = 1;i <= n;i++) {
   for (int j = 1;j <= n;j++) {
    if (j < i) {
     book[i][a[j]].c1++;
    }
    else if (j > i) {
     book[i][a[j]].c2++;
    }
    if (book[i][a[j]].c1 && book[i][a[j]].c2) {
     f = 1;
     puts("YES");
     break;
    }
   }
   if (f) break;
  }
  if (!f) puts("NO");
 }
 return 0;
}

1324C - Frog Jumps

#include<iostream>
#include<string>
#include<unordered_set>
#include<vector>
#include<queue>
#include<set>
#include<cmath>
#include<iomanip>
#include<string>
#include<string.h>
#include<map>
#define INF 0x3f3f3f3f;
const int maxn = 1e9 + 5;
using namespace std;
int t , l;
string s;
bool check(int x) {
 int last = -1;
 for(int i = l - 1;i >= 0;i--) {
  if (s[i] == 'R') {
   if (last != -1 && last - i > x)
   {
    return false;
   }
   last = i;
  }
 }
 if (last != -1 && last + 1 <= x) return 1;
 return 0;
}
int main() {
 ios::sync_with_stdio(false);
 cin.tie(false);
 cin >> t;
 while(t--) {
  cin >> s;
  l = s.length();
  int L = 1, R = l+1;
  for (int i = l - 1;i >= 0;i--) {
   if (s[i] == 'R') {
    L = l - i;
    break;
   }
  }
  //cout << "R: " << R << endl;
  while (L < R) {
   int mid = (L + R) >> 1;
   if (check(mid)) {
    R = mid;
    //cout << mid << " OK" << endl;
   }
   else {
    L = mid+1;
    //cout << mid << " tNOT OK" << endl;
   }
  }
  cout << L << endl;
 }
 return 0;
}

1324D - Pair of Topics
(1)二分
一个二分想了好久 果然又是long long 的问题orz
觉得有必要整理一下二分模板了

#include<iostream>
#include<string>
#include<unordered_set>
#include<vector>
#include<queue>
#include<set>
#include<cmath>
#include<iomanip>
#include<string>
#include<string.h>
#include<map>
#define INF 0x3f3f3f3f;
const int maxn = 2 * 1e5 + 5;
using namespace std;
int n,a[maxn],b[maxn];
long long ans;
bool check(int x,int y) {
 return a[x] + a[y] >0 ;
}
int main() {
 ios::sync_with_stdio(false);
 cin.tie(false);
 cin >> n;
 for (int i = 1;i <= n;i++) cin >> a[i];
 for (int i = 1;i <= n;i++) { cin >> b[i]; a[i] -= b[i]; }
 sort(a + 1, a + 1 + n);
 for (int i = 1;i <= n;i++) {
  long long L = i + 1, R = n;
  while (L < R) {
   long long  mid = (L + R) >> 1;
   if (check(i,mid)) {
    //cout << mid << " OK" << endl;
    R = mid;
   }
   else {
    //cout << mid << " NOT OK" << endl;
    L = mid+1;
   }
  }
  //cout << "+" << n - L+1 << endl;
  if(check(i,L)) ans += (n - L+1);
 }
 cout << ans << endl;
 return 0;
}

另一种做法用到了
(2)树状数组
用来求和
也复习一下树状数组吧
1324E - Sleeping Schedule
dp了
预处理注意

#include<iostream>
#include<string>
#include<unordered_set>
#include<vector>
#include<queue>
#include<set>
#include<cmath>
#include<iomanip>
#include<string>
#include<string.h>
#include<map>
#define INF 0x3f3f3f3f;
const int maxn = 2 * 1e3 + 5;
using namespace std;
int n, h, l, r;
int t[maxn],dp[maxn][maxn];
int main() {
 ios::sync_with_stdio(false);
 cin.tie(false);
 cin >> n >> h >> l >> r;
 for (int i = 0;i <= n;i++) {
  for (int j = 0;j <= h;j++) {
   dp[i][j] = -0x3f3f3f3f;
  }
 }
 dp[0][0] = 0;
 for (int i = 1;i <= n;i++) cin >> t[i];
 for (int i = 1;i <= n;i++) {
  for (int j = 0;j < h;j++) {
   dp[i][j] = max(dp[i-1][(j-t[i]+h)%h], dp[i-1][(j-t[i]+1+h)%h]);
   dp[i][j] += (j >= l && j <= r);
  }
 }
 int ans = 0;
 for (int i = 0;i < h;i++) {
  ans = max(ans, dp[n][i]);
 }
 cout << ans << endl;
 return 0;
}

二 Div3(1328)
A - Divisibility Problem
签到

#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<unordered_map>
#include<string>
#include<map>
#include<string.h>
#define inf 2e9
using namespace std;
const int maxn = 1e5 + 5;
int a,b,t;
int main() {
 cin >> t;
 while (t--) {
  cin >> a >> b;
  if (a%b == 0) cout << 0 << endl;
  else {
   cout << b - a % b << endl;
  }
 }
 return 0;
}

B - K-th Beautiful String
构造1+2+…+n
longlong引发的惨案+1,一气之下全开了longlong

#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<unordered_map>
#include<string>
#include<map>
#include<string.h>
#define inf 2e9
using namespace std;
const int maxn = 1e5 + 5;
 
long long n,t;
long long k;
int main() {
 cin >> t;
 while (t--) {
  cin >> n >> k;
  long long l = 0,d=0;
  string ans;
  for (long long i = 1;i <= maxn;i++) {
  long long test = i*(i-1)/2;
   if (test>= k) {
    l = i;
    d = test - k;
    break;
   }
  }
  for (int i = 1;i <= n - l;i++) {
   ans += 'a';
  }
  ans += 'b';
  for (int i = 1;i <= d;i++) {
   ans += 'a';
  }
  ans += 'b';
  for (int i = 1;i <= l - d - 2;i++) {
   ans += 'a';
  }
  cout <<ans<< endl;
 }
 return 0;
}

C - Ternary XOR
方法是贪心,思想是构造

#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<unordered_map>
#include<string>
#include<map>
#include<string.h>
#define inf 2e9
using namespace std;
const int maxn = 1e5 + 5;
int t, n;
string x;
int main() {
 cin >> t;
 while (t--) {
  string a, b;
  bool ok = 0;
  cin >> n >> x;
  for (int i = 0;i < x.length();i++) {
   if (x[i] == '0') {
    a += '0';b += '0';
   }
   if (x[i] == '1') {
    if (!ok) {
     a += '1';b += '0';
     ok = 1;
    }
    else {
     a += '0';b += '1';
    }
   }
   if (x[i] == '2') {
    if (!ok) {
     a += '1';b += '1';
    }
    else {
     a += '0';b += '2';
    }
   }
  }
  cout << a << endl << b << endl;
 }
 return 0;
}

D - Carousel
有必要说一下题意(一直以为题意错了
共有n个位置,给出很多动物种类,排成一个环,每个位置放一个动物,染色,要求相邻的不同种类动物不能拥有相同的颜色,求最小颜色数量。
一开始莫名其妙联想到了四色定理,然后GG
一波模拟挂了,不知何解。
思路大致如下:如果相同动物连在一起,涂相同的颜色;如果相邻颜色不同,间隔开涂;唯一可能造成答案为3的情况是因为是环,涂到第n个的时候发现与第一个冲突了,而又不能改成与n-1相同的颜色,所以要加一得到3.
过了。。要分奇偶讨论,并且所有数字一样的时候特判答案是1

当有循环结构的时候,下标1-n没有0-n-1愉悦

#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<unordered_map>
#include<string>
#include<map>
#include<string.h>
#define inf 2e9
using namespace std;
const int maxn = 3e5 + 5;
int q, n,a[maxn],ans[maxn];
int main() {
 cin >> q;
 while (q--) {
  cin >> n;
  int tot = 1;
  for (int i = 1;i <= n;i++) cin >> a[i];
  bool f = 1;
  for (int i = 1;i <= n;i++) {
   if (a[i] != a[1]) {
    f = 0;
    break;
   }
  }
  if (f) {
   for (int i = 1;i <= n;i++)
    ans[i] = 1;
  }
  else {
   if (n % 2 == 0) {
    tot++;
    for (int i = 1;i <= n;i++) {
     ans[i] = i % 2 ==0 ? 1 : 2;
    }
   }
   else {
    bool okk = 0;
    //虽然n是奇数,但凡有1个重复的,都可以转化为偶数解决问题
    for (int i = 1;i <= n;i++) {
     if (i == n && a[i] == a[1] && !okk) {
      okk = 1;ans[i] = ans[1];
     }
     if (a[i] == a[i - 1] && !okk) {
      okk = 1; ans[i] = ans[i - 1];
     }
     else {
      ans[i] = ans[i - 1] == 1 ? 2 : 1;
     }
    }
    if (okk) tot = 2;
    else tot = 3, ans[n] = 3;
   }
  }
  cout << tot << endl;
  for (int i = 1;i <=n;i++) 
   cout << ans[i] << " ";
  cout <<endl;
 }
  return 0;
}

三 周末练习
cf好像裂开了 自闭中
题意
B 一个读题的 签到

//B
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
#include <set>
#include <cmath>
#include <vector>
#include <queue>
#include<string.h>
#include <string>
#define pi pcos(-1.0)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
string s;
int main() {
 cin.tie(false);
 ios::sync_with_stdio(false);
 cin >> s;
 int cc = 0,ss = 0;
 for (int i = 0;i < s.length();i++) {
  if (s[i] == 'C') {
   cc++;
   if (cc == 3) {
    cc = 0;
    cout << "P";
   }
   else
    cout << "B";
   ss = 0;
  }
  else {
   ss++;
   if (ss == 3) {
    ss = 0;
    cout << "T";
   }
   else cout << "D";
   cc = 0;
  }
 }
 return 0;
}

C DFS
终于敲出来了,和数独差不多 开几个数组记录
以下来自dalao代码

//i
#include"pch.h"
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
#include <set>
#include <cmath>
#include <vector>
#include <queue>
#include <string>
#define pi pcos(-1.0)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int maxn = 3e5 + 5;
bool vis[10][10], col[10][10], row[10][10], reg[40][10],b[10][10];
int mp[10][10], n,v[40],cur[40],a[10][10];
int process(string x) {
 int res = 0;
 for (int i = 0;i < x.length();i++) {
  res *= 10;
  res += x[i] - '0';
 }
 return res;
}
bool ok() {
 for (int i = 1;i <= n;i++)cur[i] = 0;
 for (int i = 1;i <= 6;i++) {
  for (int j = 1;j <= 6;j++) {
   cur[mp[i][j]] += a[i][j];
  }
 }
 for (int i = 1;i <= n;i++) {
  if (cur[i] != v[i]) return 0;
 }
 return 1;
}
void print() {
 for (int i = 1;i <= 6;i++) {
  for (int j = 1;j <= 6;j++) {
   cout << a[i][j] << " ";
  }
  cout << endl;
 }
}
int id(int x, int y) {
 return (x - 1) / 2 * 2 + (y - 1) / 3 + 1;
}
bool can(int x, int y, int i) {
 if (!(row[x][i]) && !col[y][i] && !b[id(x, y)][i] && !reg[mp[x][y]][i]) {
  if (cur[mp[x][y]] + i <= v[mp[x][y]])return 1;
 }
 return 0;
}
void deal(int x, int y, int i, int f) {
 a[x][y] = i;
 row[x][i] = col[y][i] = b[id(x, y)][i] = reg[mp[x][y]][i] = f;
 if (f) {
  cur[mp[x][y]] += i;
 }
 else {
  cur[mp[x][y]] -= i;
 }
 return;
}
bool dfs(int x, int y) {
 if (x == 7) {
  if (ok()) return 1;
  return 0;
 }
 bool f = 0;
 for (int i = 1;i <= 6;i++) {
  if (can(x, y, i)) {
   deal(x, y, i, 1);
   if (y < 6) f = dfs(x, y + 1);
   else f = dfs(x + 1, 1);
   if (f)return 1;
   deal(x, y, i, 0);
  }
 }
 return 0;
}
int main() {
 cin >> n;for (int i = 1;i <= n;i++)cin >> v[i];
 for (int i = 1;i <= 6;i++){
  for (int j = 1;j <= 6;j++) {
   string x;cin >> x;
   mp[i][j] = process(x);
  }
 }
 dfs(1, 1);
 print();
 return 0;
}

这是我的代码,比较(非常 )丑
注释掉的部分是cur数组的正确用法,至于我这样的,完全就是浪费时间啊…不知会不会tle,不过正确用法比上面那个快一点点耶(转圈圈
解除标记的时候要记得减去cur,如果不用记录,那就要清空a数组,这就是debug一下午的原因((

//c
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
#include <set>
#include <cmath>
#include <vector>
#include <queue>
#include <string>
#define pi pcos(-1.0)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int maxn = 3e5 + 5;
bool vis[10][10], col[10][10], row[10][10], reg[40][10],b[10][10];
int mp[10][10], n,v[40],cur[40],a[10][10];
int process(string x) {
 int res = 0;
 for (int i = 0;i < x.length();i++) {
  res *= 10;
  res += x[i] - '0';
 }
 return res;
}
bool ok() {
 for (int i = 1;i <= n;i++)cur[i] = 0;
 for (int i = 1;i <= 6;i++) {
  for (int j = 1;j <= 6;j++) {
   cur[mp[i][j]] += a[i][j];
  }
 }
 for (int i = 1;i <= n;i++) {
  if (cur[i] != v[i]) return 0;
 }
 return 1;
}
void print() {
 for (int i = 1;i <= 6;i++) {
  for (int j = 1;j <= 6;j++) {
   cout << a[i][j] << " ";
  }
  cout << endl;
 }
 cout << endl;
}
bool notok() {
 for (int i = 1;i <= n;i++)cur[i] = 0;
 for (int i = 1;i <= 6;i++) {
  for (int j = 1;j <= 6;j++) {
   cur[mp[i][j]] += a[i][j];
  }
 }
 for (int i = 1;i <= n;i++) {
  if (cur[i] > v[i]) { 
   return 1; 
  }
 }
 return 0;
}
bool flag = 0;
void findans(int r,int c) {
 if (flag)return;
 if (r == 7) {
  if (ok()) { print(); flag = 1; }
  return;
 }
 for (int i = 1;i <= 6;i++) {
  if (!row[r][i] && !col[c][i]
   && !b[(r - 1) / 2 * 2 + (c - 1) / 3 + 1][i]
   && !reg[mp[r][c]][i]
   && !notok()) {
   row[r][i] = col[c][i] = 1;
   b[(r - 1) / 2 * 2 + (c - 1) / 3 + 1][i] = 1;
   reg[mp[r][c]][i] = 1;
   a[r][c] = i;
   //cur[mp[r][c]] += i;
   if (flag) return;
   else if (c == 6) findans(r + 1, 1);
   else findans(r, c + 1);
   row[r][i] = col[c][i] = 0;
   b[(r - 1) / 2 * 2 + (c - 1) / 3 + 1][i] = 0;
   reg[mp[r][c]][i] = 0;
   a[r][c] = 0;
   //cur[mp[r][c]] -= i;
  }
 }
 return;
}
int id(int x, int y) {
 return (x - 1) / 2 * 2 + (y - 1) / 3 + 1;
}
int main() {
 cin >> n;for (int i = 1;i <= n;i++)cin >> v[i];
 for (int i = 1;i <= 6;i++){
  for (int j = 1;j <= 6;j++) {
   string x;cin >> x;
   mp[i][j] = process(x);
  }
 }
 findans(1,1);
 return 0;
}

D. Doll Collector 签到
求出最大的满足n*(n+1)/2 < x的n即可(x为输入值)

E
FFT, 菜鸡还没有真正学会过。。

F. Frieza Frenzy
队友写的 据说是并查集 然而我GG了
顺道回去复习了并查集,准备补带权值的并查集了((真就递归学习啊
噢 原来是一个倒着的并查集,利用了起始连通的条件。
倒着看,假设起始时所有点离散,当一个点被拆除(即进行连接操作)时,与他相连的所有边(如果他们本来不相连)变为一个联通块,更新联通块的个数,直到最后所有点都连通。
因为这里是倒着来的,所以答案也倒着输出,用减法统计。

//i
#include"pch.h"
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
#include <set>
#include <cmath>
#include <vector>
#include <queue>
#include <string>
#define pi pcos(-1.0)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define mp make_pair
using namespace std;
const int maxn = 1e5 + 5;
int n, m,d[maxn],ans[maxn],f[maxn];
struct E {
 int u, v;
}edge[maxn];
int find(int x) {
 return f[x] == x ? x : find(f[x]);
}
void merge(int x, int y) {
 f[x] = y;
 return;
}
int main() {
 cin >> n >> m;
 for (int i = 1;i <= m;i++) {
  cin >> edge[i].u >> edge[i].v;
 }
 for (int i = 1;i <= m;i++) cin >> d[i];
 for (int i = 1;i <= n;i++)f[i] = i;
 int cnt = n;
 for (int i = m;i >= 1;i--) {
  int x = find(edge[d[i]].u);
  int y = find(edge[d[i]].v);
  if (x != y) {
   cnt--;
   merge(x, y);
  }
  ans[i-1] = cnt;
 }
 ans[m] = n;
 for (int i = 1;i <= m;i++) {
  cout << ans[i] << endl;
 }
 return 0;
}

G 看起来像是数学题

H. Heaven’s Arena
cout << n+0.01*(ap+(-a)(100-p))<<endl
即可

I. Important Equipment
计算几何 我要鞭挞我自己 最后还是要靠好队友
一直在看,从没有写出来过
两种方法
(1)求交点个数-神奇的结论(适用于任何多边形)
经过一点任意作一条射线(为了方便我们一般做与xy轴垂直的线哈),求解出与多边形每条边所在直线的交点总个数,
若为奇数,则此点在多边形外部;
若为偶数,则此点在多边形内部。
代码明天明天吧qwq 噫在睡前写完了,不过已经是明天了
比较多细节,要判断与边重合、在边上,不考虑水平线
,考虑垂直线,如果不是垂线那么x交点要在右侧才可加入有效计数。

交点法还没debug出来 假代码
请注意 是错的嗷

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
#include <set>
#include <cmath>
#include <vector>
#include <queue>
#include<string.h>
#include <string>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int maxn = 1e3 + 5;
const double eps = 1e-5;
int s, r, m,n;
struct P {
 int x, y;
};
struct A {
 P stk[maxn];
 int top;
}a[5];
bool onesegment(P pi, P pj, P Q) {
 //判断是否共线 叉积等于0且在线段上
 if ((Q.x - pi.x)*(pj.y - pi.y) == (pj.x - pi.x)*(Q.y - pi.y)
  && min(pi.x, pj.x) <= Q.x && max(pi.x, pj.x) >= Q.x
  && min(pi.y, pj.y) <= Q.y && max(pi.y, pj.y) >= Q.y)
  return true;
 return false;
}
bool insidepolpgon(P t,int id) {
 int cnt = 0;
 double xinters;
 P p1 = a[id].stk[0],p2;
 for (int i = 0;i < a[id].top;i++) {
  p2 = a[id].stk[i % (a[id].top)];
  if (onesegment(p1, p2, t))
   return true;
  //水平边不做考虑,首先要在范围内
  if (t.y > min(p1.y, p2.y) &&
   t.y <= max(p1.y, p2.y)&&
   t.x <= max(p1.x, p2.x)&&
   p1.y != p2.y) 
  {
   xinters = (t.y - p1.y)*(p2.x - p1.x) / (p2.y - p1.y) + p1.x;
   if (p1.x == p2.x || t.x <= xinters)
    cnt++;
  }
  p1 = p2;
 }
 if (cnt % 2 == 0) return false;
 return true;
}
string ans(int id) {
 if (id == 0)return "Sheena";
 if (id == 1)return "Rose";
 if (id == 2)return "Maria";
 return "";
}
void process(int n, int id) {
 for (int i = 1;i <= n;i++) {
  int xx, yy; cin >> xx >> yy;
  int num = a[id].top;
  a[id].stk[num].x = xx;a[id].stk[num].y = yy;
  a[id].top++;
 }
}
int main() {
 cin.tie(false);
 ios::sync_with_stdio(false);
 cin >> s >> r >> m;
 process(s, 0);process(r, 1);process(m, 2);
 P t;cin >> n;
 for (int i = 1;i <= n;i++) {
  cin >> t.x >> t.y;
  bool flag = 0;
  for (int id = 0;id < 3 && !flag;id++) {
   if (insidepolpgon(t, id)) {
    flag = true;
    cout << ans(id) << endl;
   }
  }
  if (!flag) cout << "Outside" << endl;
 }
 return 0;
}

(2)叉积 -(只适用于凸多边形的算法)
自己又加了一个判断条件,cf炸了还没来得及交,明天交交看。

至少在无限debug的痛苦中我再一次复习了无数遍叉积
(x1y2-x2y1)设三点分别为P1,P2,P0,
那么以P0为向量的出发点,叉积为
X(p1-p0)*Y(p2-p0)-X(p2-p0)*Y(p1-p0)
超大声bb

以及学会了判断点在直线左边、右边还是直线上的方法:也是叉积

左边>0,右边<0,直线上=0(以P0为向量出发点)

以及找出了练习时一直GG的原因,因为判断的时候点落在了某块多边形区域的延长线上,虽然不在但是判断是=0的并没有异号所以就漏掉了。
真是悲伤的故事啊

(更新于第二天(x)
debug了一上午 发现是longlong的问题
自 我 枪 毙

//i
#include"pch.h"
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
#include <set>
#include <cmath>
#include <vector>
#include <queue>
#include<string.h>
#include <string>
#define pi pcos(-1.0)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef long long ll;
using namespace std;
const int maxn = 1e3 + 5;
int s, r, m, n;
struct P {
 int x, y;
};
struct A {
 P stk[maxn]; int top;
 int minx, maxx, miny, maxy;
}a[3];
void process(int n, int id) {
 a[id].maxx = a[id].maxy = 0;
 a[id].minx = a[id].miny = maxn;
 for (int i = 1;i <= n;i++) {
  int xx, yy; cin >> xx >> yy;
  int num = a[id].top;
  a[id].stk[num].x = xx;a[id].stk[num].y = yy;
  a[id].top++;
  a[id].maxx = max(a[id].maxx, xx);a[id].maxy = max(a[id].maxy, yy);
  a[id].minx = min(a[id].minx, xx);a[id].miny = min(a[id].miny, yy);
 }
}
//没错就是这里 嘤嘤嘤
ll multi(P p1, P p2, P p0) {
 ll ans = (ll)((ll)((p1.x - p0.x)*(ll)(p2.y - p0.y))) - (ll)((ll)(p2.x - p0.x)*(ll)(p1.y - p0.y));
 return  ans;
}
//这个可以省略 不知到会不会快些
bool out(P p, A a) {
 if (p.x<a.minx || p.x>a.maxx || p.y<a.miny || p.y>a.maxy)
  return true;
 return false;
}
bool isinside(P p, A a) {
//此句可省
 if (out(p, a)) return false;
 //
 for (int i = 0;i < a.top;i++) 
  if (multi(a.stk[i], a.stk[(i + 1) % a.top], p) < 0) 
   return false;
 return true;
}
string ans(int id) {
 if (id == 0)return "Sheena";
 if (id == 1)return "Rose";
 if (id == 2)return "Maria";
 return "";
}
int main() {
 cin.tie(false);ios::sync_with_stdio(false);
 cin >> s >> r >> m; process(s, 0);process(r, 1);process(m, 2);
 cin >> n; 
 while(n--){
  P t; cin >> t.x >> t.y; bool flag = 0;
  for (int id = 0;id < 3 && !flag;id++) {
   if (isinside(t, a[id])) {
    flag = true; cout << ans(id) << endl;
   }
  }
  if (!flag) cout << "Outside" << endl;
 }
 return 0;
}

ok了,好累

J - Jaeger Training
寻找s[i]前值大于等于s[i]的个数,队友写的,据说归并排序模板可

更新于两天后-------补完了,确实是归并排序改一改,更新答案记得标记序号
归并时候的逆序数(不是严格意义上的逆序数,因为相等也算)与这个数所处的位置有关,
ans[num]+=他前面的个数
写完一瞄,几乎和队友一模一样。。可能是模板的原因吧orz

//i
#include"pch.h"
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
#include <set>
#include <cmath>
#include <vector>
#include <queue>
#include <string>
#define pi pcos(-1.0)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int maxn = 5e5 + 5;
int n,ans[maxn];
struct P {
 int v, id;
}s[maxn], tmp[maxn];
void mergearray(P a[], int L,int mid, int R, P t[]) {
 int i = L, j = mid + 1, mm = mid, nn = R,k=0;
 while (i <= mm && j <= nn) {
  if (a[i].v < a[j].v) t[k++] = a[i++];
  else {
   t[k++] = a[j]; ans[a[j++].id] += mm - i + 1;
   //cout << ans[j] << endl;
  }
 }
 while (i <= mm) t[k++] = a[i++];
 while (j <= nn) t[k++] = a[j++];
 for (int i = 0;i < k;i++) a[L + i] = t[i];
}
void mergesort(P a[], int L, int R, P t[]) {
 if (L < R) {
  int mid = (L + R) >> 1;
  mergesort(a, L, mid, t);
  mergesort(a, mid + 1, R, t);
  mergearray(a, L, mid, R, t);
 }
 return;
}
int main() {
 cin.tie(false);ios::sync_with_stdio(false);
 cin >> n;for (int i = 0;i < n;i++) {cin >> s[i].v; s[i].id = i;}
 mergesort(s, 0, n - 1, tmp);
 //for (int i = 0;i < n;i++)cout << s[i].v << endl;
 for (int i = 0;i < n;i++) { cout << n-ans[i] << " "; }
 return 0;
}

K. Killua’s Race 图论
这个还没懂…

L 记忆化dp
建图有点复杂…TLE

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
#include <set>
#include <cmath>
#include <vector>
#include <queue>
#include <string>
#define pi pcos(-1.0)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int maxn = 1e5 + 5, inf = 0x3f3f3f3f;
int n, l,dp[maxn];
struct P {
 int x, y;
 bool operator<(P &a) {
  if (x != a.x) return x < a.x;
  return y < a.y;
 }
}p[maxn];
struct node {
 int y, index;
 node(int a, int b) {
  y = a;index = b;
 }
 bool operator<(node & a) {
  if (a.y != y) return y < a.y;
  return index < a.index;
 }
};
map<int, pair<int, int>> f;
set<int> s;
vector<node> id[maxn];
vector<int> X[maxn], edge[maxn];
int DFS(int u) {
 if (dp[u]) return dp[u];
 int res = 0;
 for (auto v:edge[u]) {
  res = max(res, DFS(v));
 }
 if (edge[u].size() == 0) {
  //可以到达
  if (u == n + 1) return dp[u] = 1;
  else return dp[u] = -maxn;
 }
 if (res == 0) return dp[u] = -maxn;
 else return dp[u] = res + 1;
}
int main() {
 cin.tie(0);ios::sync_with_stdio(false);
 cin >> n >> l;
 p[0].x = p[0].y = 0;
 p[n + 1].x = l;p[n + 1].y = 0;
 X[0].push_back(0);
 id[0].push_back(node(0, 0));
 X[l].push_back(0);
 id[l].push_back(node(0, n + 1));
 f[0] = make_pair(0, 0);
 f[n + 1] = make_pair(l, 0);
 s.insert(0);s.insert(l);
 for(int i = 1;i <= n;i++) {
  cin >> p[i].x >> p[i].y;
  id[p[i].x].push_back(node(p[i].y,i));
  X[p[i].x].push_back(p[i].y);
  s.insert(p[i].x);
  f[i] = make_pair(p[i].x, p[i].y);
 }
 sort(p, p + n + 2);
 for (auto i = s.begin();i != s.end();i++) {
  int k = *i;
  sort(X[k].begin(), X[k].end());
  sort(id[k].begin(), id[k].end());
 }
 //这是优化,只在可能的范围内找出符合条件的点,建边
 //约束条件(x+=5,abs相加小于5),使用X存储(x,y),id存储y对应的序号,如果不是重复点就建边
 for (int i = 0;i <= n;i++) {
  int x = f[i].first;
  int y = f[i].second;
  for (int xx = x + 1;xx <= x + 5;xx++) {
   int d = 5 - (xx - x);
   int pos1 = lower_bound(X[xx].begin(), X[xx].end(), y - d) - X[xx].begin();
   int pos2 = upper_bound(X[xx].begin(), X[xx].end(), y + d) - X[xx].begin();
   //没找到
   if (pos1 == X[xx].size()) continue;
   //全都符合
   if (pos2 == X[xx].size()) pos2 = X[xx].size() - 1;
   for (int k = pos1; k <= pos2;k++) {
    int idd = id[xx][k].index;
    int yy = id[xx][k].y;
    if (abs(yy - y) + abs(xx - x) > 5) continue;
    //if (i != idd) {
     //建边
     edge[i].push_back(idd);
    //}
   }
  }
 }
 //减2是因为开头结尾
 cout << DFS(0) - 2 << endl;
 return 0;
}

ECNA 2016 又开新坑

B - Foosball Dynasty
模拟(其实我挺喜欢做模拟(小声bb 这大概就是菜狗吧
从下午debug到晚上
使用map记录每个人加入的时间,然后注意一下题目要求
以及:get swap对于string可能会造成迭代器失效

#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<unordered_map>
#include<string>
#include<map>
#include<string.h>
#define inf 2e9
using namespace std;
const int maxn = 1e5 + 5;
int n,last;
map<string, int> mp;
struct P {
 int id;
 string df, of;
}w, b;
struct Team {
 string  fis,sec;
};
Team team[maxn];int tot = 0;
string info;
queue<string> q;
int cur=0,rec;
void okk(P &win,P &lose) {
 //cur记录的是最长连胜数
 if (last == win.id) 
  cur++;
 else {
  last = 1-last;
  cur = 1;
 }
 Team m;
 if (cur >= rec) {
  if (mp[win.df] > mp[win.of]) {
    m.fis = win.df; m.sec = win.of;
  }
  else {
   m.fis = win.of;m.sec = win.df;
  }
  tot = (cur == rec ? tot: 0);
  team[++tot] = m;
  rec = cur;
 }
 /*
 string tmp = win.df;
 win.df = win.of;
 win.of = tmp;
 */
 //SWAP函数对string函数容易造成迭代器失效
 swap(win.df, win.of);
 string now = q.front();q.pop();
 q.push(lose.df);
 lose.df = lose.of;
 lose.of = now;
 mp[lose.df] = 2;
 mp[lose.of] = 1;
}
void print() {
 for (int i = 1;i <= tot;i++) 
  cout << team[i].fis << " " << team[i].sec << endl;
 
}
int main() {
 cin >> n;
 w.id = 0;b.id = 1;
 cin >> w.of >> b.of >> w.df >> b.df;
 mp[w.of] = mp[b.of] = 2;mp[w.df] =mp[b.df]=1;
 for (int i = 5;i <= n;i++) {
  string x;cin >> x;
  q.push(x);
 }
 cin >> info;
 if (info[0] == 'W') last = 0;
 else last = 1;
 for (int i = 0;i < info.length();i++) {
  if (info[i] == 'W')  okk(w, b);
  else  okk(b, w);
 }
 print();
 return 0;
}

C-The Key to Cryptography

#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<string>
#include<string.h>
#define inf 2e9
using namespace std;
const int maxn = 3e5+5;
int main() {
 string s, t,ans;
 cin >> s >> t;
 for (int i = 0;i < s.length();i++) {
  char x = char((s[i] - t[i] + 26)%26 +'A');
  ans += x;
  t += x;
 }
 cout << ans << endl;
 return 0;
}

D Lost in Translation
BFS也可以用MST
真的自闭了

#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<string>
#include<map>
#include<string.h>
#define inf 2e9
using namespace std;
const int maxn = 3e3 + 5;
map<string, int> mp;
int n, m, res;
struct P {
 int nxt, to, w;
}edge[maxn];
int E[maxn][maxn];
vector<int> Dep[maxn];
int dis[maxn], ans[maxn];
void bfs() {
 queue<int>Q;
 memset(dis, -1, sizeof(dis));
 int st = 1;Q.push(st);
 dis[st] = 0;ans[st] = 0;
 while (!Q.empty()) {
  int u = Q.front();Q.pop();
  for (int i = 1;i <= n + 1;i++) {
   if (E[u][i] && (dis[i] == -1 || dis[i] >= dis[u] + 1)) {
    if(dis[i]!=dis[u]+1)
     dis[i] = dis[u] + 1;
    ans[i] = min(ans[i], E[u][i]);
    Q.push(i);
   }
  }
 }
 return;
}
int main() {
 memset(head, -1, sizeof(head));
 scanf_s("%d%d", &n, &m);
 for (int i = 1;i <= n;i++) {
  string s; cin>>s;
  mp[s] = i + 1;
  ans[i + 1] = inf;
 }
 mp["English"] = 1;ans[1] = inf;
 for (int i = 1;i <= m;i++) {
  string u, v;int w;
  cin >> u >> v >> w;
  E[mp[u]][mp[v]] = w;
  E[mp[v]][mp[u]] = w;
 }
 bfs();
 for (int i = 1;i <= n + 1;i++) {
  if (dis[i] == -1) {
   puts("Impossible");
   return 0;
  }
  else res+=ans[i];
 }
 printf("%d\n", res);
 return 0;
}

另一种写法orz

#include"pch.h"
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<unordered_map>
#include<string>
#include<map>
#include<string.h>
#define inf 2e9
using namespace std;
const int maxn = 1e5 + 5;
struct E {
 int nxt, to, w;
}edge[maxn << 1];
int head[maxn], tot = 0,vis[maxn];
void add(int u, int v, int w) {
 edge[tot].to = v;
 edge[tot].w = w;
 edge[tot].nxt = head[u];
 head[u] = tot++;
}
unordered_map<string, int> mmp;
int n, m,res;
#define f first
#define s second
#define mp make_pair
#define pii pair<int,int>
void BFS() {
 int cnt = 0;
 queue<int> Q;
 Q.push(0);vis[0] = 1;
 priority_queue<pii, vector<pii>, greater<pii>> P;
 while (cnt < n) {
  while (!Q.empty()) {
   int u = Q.front();Q.pop();
   for (int i = head[u];~i;i = edge[i].nxt) {
    if (!vis[edge[i].to]) 
     P.push(mp(edge[i].w, edge[i].to));
   }
  }
  int tmp = 0;
  while (!P.empty()) {
   auto x = P.top();P.pop();
   if (!vis[x.s]) {
    Q.push(x.s);
    vis[x.s] = 1;
    res += x.f;
    cnt++;
    tmp++;
   }
  }
  if (!tmp) break;
 }
 if (cnt < n) {
  puts("Impossible"); return;
 }
 else cout << res << endl;
}
string u, v;int w;
int main() {
 memset(head, -1, sizeof(head));
 cin >> n >> m;
 for (int i = 1;i <= n;i++) {
  cin >> u;
  mmp[u] = i;
 }
 mmp["English"] = 0;
 for (int i = 1;i <= m;i++) {
  cin >> u >> v >> w;
  add(mmp[u], mmp[v], w);add(mmp[v], mmp[u], w);
 }
 BFS();
 return 0;
}

E.Red Rover
暴力即可
不知道为什么老爱用cin

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
#include <set>
#include <cmath>
#include <vector>
#include <queue>
#include <string>
#include<string.h>
#define pi pcos(-1.0)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int maxn = 1e5;
map<string,int> mp;
string s;
int check(string x) {
 int res = 0;
 for (int i = 0;i < s.length();) {
  //cout << i << endl;
  bool f = 1;
  for (int j = 0;j < x.length() && f;j++) {
   if (s[i + j] != x[j]) { 
    f = 0;
    break; 
   }
  }
  if (f) {
   res++;
   i += x.length();
  }
  else i++;
 }
 return res;
}
int ans = 0x3f3f3f3f;
int main() {
 cin >> s;
 ans = s.length();
 for (int i = 0;i < s.length();i++) {
  for (int j = i;j < s.length();j++) {
   string t = s.substr(i, j-i+1);
   mp[t] = check(t);
   ans = min(ans,int(s.length()-mp[t]*t.length()+mp[t]+t.length()));
  }
 }
 cout << ans << endl;
 return 0;
}

F-Removal Game
区间dp
代码来自dalao

#include"pch.h"
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<unordered_map>
#include<string>
#include<map>
#include<string.h>
#define inf 2e9
using namespace std;
const int maxn = 3e3 + 5;
int n,a[maxn],dp[maxn][maxn];
int gcd(int a, int b) {
 return b == 0 ? a : gcd(b, a%b);
}
int main() {
 while (cin >> n && n) {
  for (int i = 1;i <= n;i++)  cin >> a[i];
  for (int i = 0;i <= n;i++)
   for (int j = 0;j <= n;j++)
    dp[i][j] = inf;
  for (int len = 1;len <= n-1;len++) {
   for (int i = 1;i <= n;i++) {
    int j = i + len > n ? i+len-n:i+len;
    if (len == 1) dp[i][j] = 0;
    else {
     for (int k = i + 1;k < j;k++) {
      int nk = k > n ? k - n : k;
      dp[i][j] = min(dp[i][j], dp[i][nk] + dp[nk][j] + gcd(a[i], a[j]));
     }
    }
   }
  }
  int ans = inf;
  for (int i = 1;i <= n - 1;i++) {
   for (int j = i + 1;j <= n;j++) {
    ans = min(ans, dp[i][j] + dp[j][i]+gcd(a[i], a[j]));
   }
  }
  cout << ans << endl;
 }
 return 0;
}

G - That’s One Hanoi-ed Teacher
这个有点好玩哇,汉诺塔的递推,用dfs实现的,队友写的超级短
将三根柱子命名为1,2,3,则n阶汉诺塔完成的过程可以分为以下2种情况
1.n在1上,已知f(n)=2^(n-1),可以退化为n-1阶问题,(1,3,2,n-1)
2.n在3上,把n-1个叠到他上面去(2,1,3,n-1)
n在2上不合法
(其实就是把n=2时的简单情况拓展以下,把最上面想象成n-1个)

#include<iostream>
#include<algorithm>
#include<cmath>
#define inf 1e9
using namespace std;
const int maxn = 100005;
int f[maxn];bool GG = 0;
long long ans = 0;
//移动x个盘子 从a到c
void DFS(int a, int b, int c, int x) {
 //cout << x << " from " << a << " to " << c << endl;
 if (x == 0 || GG) return;
 if (f[x] == a) {
  //最大的盘子在出发点
  ans += pow(2,x-1);
  //移动其他x-1个盘子(从出发点到终点)
  DFS(a, c, b, x - 1);
 }
 if (f[x] == b) 
  GG = 1;
 if (f[x] == c)
  //最大的盘子在终点
  //移动其他的盘子从中转点到终点
  DFS(b, a, c, x - 1);
}
int main() {
 cin.tie(0);ios::sync_with_stdio(0);
 int n = 0;
 for (int i = 1;i <= 3;i++) {
  int num;cin >> num;;
  for (int j = 1;j <= num;j++) {
   int x;cin >> x;
   n = max(n, x);
   f[x] = i;
  }
 }
 DFS(1,2,3,n);
 if (GG) cout << "No" << endl;
 else cout << ans << endl;
 return 0;
}

H BFS找出两个交叉点 标记区域(明天补
统计区域里的个数
(-------更新于第二天---------)
ok了,get了在框内选取一个点的方法,可以根据第一次出现的位置和区域的特性判断
舒 服 了

#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<unordered_map>
#include<string>
#include<map>
#include<string.h>
#define inf 2e9
using namespace std;
const int maxn = 1e5 + 5;
int r, c,tot;
int nxt[4][2] = {{0,1},{0,-1},{-1,0},{1,0} };
char M[105][105],mA[105][105],mB[105][105];
struct P {
 char id;
 int x, y;
 P():x(),y(){}
 P(int a,int b):x(a),y(b){}
 P(int a, int b, char c) :x(a), y(b), id(c) {}
}inter[3],A,B,sA,sB;
//标记是否越界
bool in(int x, int y) {
 return (x >= 1 && x <= r && y >= 1 && y <= c);
}
//判断十字
bool iscross(int x, int y) {
 return (in(x, y) && M[x][y] == 'X' &&M[x][y - 1] == 'X'&&M[x][y + 1] == 'X'&&M[x - 1][y] == 'X'&&M[x + 1][y] == 'X');
}
//是否碰到十字
bool touch(P p) {
 for (int i = 1;i <= 2;i++) 
  if (p.x == inter[i].x && p.y == inter[i].y) return 1;
 return 0;
}
//降维orz
int id(P p) {
 return (p.x - 1)*c + p.y;
}
//BFS用的,分别标记A和B,最后分别统计,在初始的图上标记改动
bool vis[maxn],book[maxn];
void inivis() {
 for (int i = 1;i <= 2;i++) vis[id(inter[i])] = 0;
}
void inibook() {
 for (int i = 1;i <= r;i++)
  for (int j = 1;j <= c;j++)
   book[id(P(i, j))] = 0;
}
void getcnt(char m[105][105],P now,int t) {
 inibook(); queue<P> QQ;
 QQ.push(now);
 book[id(now)] = 1;  M[now.x][now.y]+=t;
 while (!QQ.empty()) {
  P cur = QQ.front();QQ.pop();
  for (int k = 0;k < 4;k++) {
   P np = P(cur.x + nxt[k][0], cur.y + nxt[k][1], cur.id);
   if (in(np.x, np.y) && m[np.x][np.y] != now.id && !book[id(np)]) {
    book[id(np)] = 1;
    if (m[np.x][np.y] == '.') M[np.x][np.y]+=t;
    QQ.push(np);
   }
  }
 }
}
void BFS(char m[105][105],P cur) {
 inivis(); queue<P> Q;
 Q.push(cur); vis[id(cur)] = 1;
 while (!Q.empty()) {
  P now = Q.front();Q.pop();
  for (int k = 0;k < 4;k++) {
      P np = P(now.x + nxt[k][0], now.y + nxt[k][1], now.id);
   if (in(np.x, np.y) && !vis[id(np)] && m[np.x][np.y]!='.'){
    if (touch(np)) {
     vis[id(np)] = 1;
     m[np.x][np.y] = cur.id;
     np = P(np.x + nxt[k][0], np.y + nxt[k][1], now.id);
    }
   vis[id(np)] = 1;
   m[np.x][np.y] = cur.id;
   Q.push(np);
   }
  }
 }
}
//设第一个出现的A的坐标(i,j),则依据题意(i+1,j+1)一定落在该区域内
//所以用这个点作为bfs的起点 qwq
P findFirst(char m[105][105],char x) {
 for (int i = 1;i <= r;i++) {
  for (int j = 1;j <= c;j++) {
   if (m[i][j] == x) {
    return P(i+1, j+1, x);
   }
  }
 }
 return P(0, 0, '0');
}
void printAns() {
 int ans1=0, ans2=0, ans3=0;
 for (int i = 1;i <= r;i++) {
  for (int j = 1;j <= c;j++) {
   if (M[i][j] == '0')ans1++;
   if (M[i][j] == '1')ans2++;
   if (M[i][j] == '3')ans3++;
  }
 }
 cout << ans1 << " " << ans2 << " " << ans3 << endl;
}
int main() {
 cin >> r >> c;
 for (int i = 1;i <= r;i++) {
  for (int j = 1;j <= c;j++) {
   cin >> M[i][j];
   if (M[i][j] == 'A')A = P(i, j,'A');
   if (M[i][j] == 'B')B = P(i, j,'B');
   mA[i][j] =mB[i][j]=M[i][j];
  }
 }
 for (int i = 1;i <= r;i++) {
  for (int j = 1;j <= c;j++) {
   if (iscross(i, j)) {
    inter[++tot] = P(i, j,'X');
   }
  }
 }
 BFS(mA,A);   sA = findFirst(mA, 'A');
 BFS(mB,B);   sB = findFirst(mB,'B');
 getcnt(mA, sA, 2);   getcnt(mB, sB, 3);
 printAns();
 return 0;
}

I - Waif Until Dark
Dinic网络流O(n* n *m)
当场挂机,落泪
建立源点汇点,连接人和源点,人和玩具,玩具和种类,种类和汇点。
注意这里的边权起到约束的作用(就是网络流定义哇),没有种类归属的玩具可以直接与汇点相连,个数限制无限个
WA了一次是因为 把人和源点之间的权值设置成了+oo,应该是1,因为只需要保证每个人一个玩具就可

#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<string.h>
#define inf 2e9
using namespace std;
const int maxn = 3e5+5;
//网络最大流模板
//注意edge两倍大小哇
struct P {
 int nxt, to, w;
}edge[maxn];
int tot=-1, n, m,p, head[maxn];
void add(int u, int v, int w) {
 edge[++tot].nxt = head[u];
 edge[tot].to = v;
 edge[tot].w = w;
 head[u] = tot;
}
int ans,S,T;
int dis[maxn],book[maxn];
queue<int> Q;
int bfs() {
 memset(dis, -1, sizeof(dis));
 while (!Q.empty()) Q.pop();
 dis[S] = 0;
 Q.push(S);
 //BFS计算层数
 while (!Q.empty()) {
  int u = Q.front();
  Q.pop();
  for (int i = head[u];i != -1;i = edge[i].nxt) {
   int v = edge[i].to;
   if (dis[v] == -1 && edge[i].w) {
    dis[v] = dis[u] + 1;
    Q.push(v);
   }
  }
 }
 //能否到达汇点
 return dis[T] != -1;
}
//把int写成bool,我怕不是个傻子吧..........
int dfs(int u, int exp) {
 if (u == T) return exp;
 int flow = 0, tmp = 0;
 for (int i = head[u];i != -1;i = edge[i].nxt) {
  int v = edge[i].to;
  if (dis[v] == dis[u] + 1 && edge[i].w) {
   tmp = dfs(v, min(exp, edge[i].w));
   if (!tmp) continue;
   exp -= tmp;
   flow += tmp;
   edge[i].w -= tmp;
   //^1代表反向边
   edge[i ^ 1].w += tmp;
  }
  if (!exp) dis[u] = 0;
 }
 return flow;
}
int main() {
 memset(head, -1, sizeof(head));
 scanf_s("%d%d%d", &n, &m, &p);
 S = 0;T = n + m + p + 1;
 for (int i = 1;i <= n;i++) {
  //连接人和源点
  add(S, i, 1);add(i, S, 0);
  int t;scanf_s("%d", &t);
  for (int j = 1;j <= t;j++) {
   int id;scanf_s("%d", &id);
   //人和玩具
   add(i, n+id, 1);
   add(n+id, i, 0);
  }
 }
 for (int i = 1;i <= p;i++) {
  int t;scanf_s("%d", &t);
  for (int j = 1;j <= t;j++) {
   int id;scanf_s("%d", &id);
   book[id]=1;
   //玩具和种类
   add(n + id, n+m+i, 1);
   add(n+m+i, n + id, 0);
  }
  int lim;scanf_s("%d", &lim);
  //种类和汇点
  add(m + n + i, T, lim);
  add(T, m + n + i, 0);
 }
 for (int i = 1;i <= m;i++) {
  if (!book[i]) {
   //没有种类约束的玩具,直接连接到汇点
   //只能选1个
   add(n+i, T, 1);
   add(T, n+i, 0);
  }
 }
 while (bfs()) ans += dfs(S, inf);
 printf("%d\n", ans);
 return 0;
}

经过此题,收获了一个优雅(并不)的板子

发布了24 篇原创文章 · 获赞 2 · 访问量 952

猜你喜欢

转载自blog.csdn.net/weixin_43521836/article/details/104886510