2019nc#5
题号 | 标题 | 已通过代码 | 题解/讨论 | 通过率 | 团队的状态 |
---|---|---|---|---|---|
A | digits 2 | 点击查看 | 1017/2384 | 通过 | |
B | generator 1 | 点击查看 | 567/3692 | 通过 | |
C | generator 2 | 点击查看 | BSGS | 38/640 | 未通过 |
D | generator 3 | 点击查看 | 4/23 | 未通过 | |
E | independent set 1 | 点击查看 | 位元状压DP | 48/115 | 未通过 |
F | maximum clique 1 | 点击查看 | 二分图最大独立集 | 98/849 | 👌 |
G | subsequence 1 | 点击查看 | 基础DP | 530/2540 | 通过 |
H | subsequence 2 | 点击查看 | 290/1399 | 通过 | |
I | three points 1 | 点击查看 | 计算几何 | 142/2722 | 未通过 |
J | three points 2 | 点击查看 | 树DP | 7/76 | 未通过 |
F maximum clique 1
题意
在n个数中,找出最多的子集,要求集合中任意两个数在二进制下不会出现只有一位不同。
思路
我们把只有一位数不同的点对相连。
注意到这个图是没有奇环的,所以是一个二分图,然后就是求二分图最大独立集的问题了。
学习这篇blog的思路就可以写出来
https://www.cnblogs.com/jianglangcaijin/p/6035945.html
// #pragma GCC optimize(2) // #pragma GCC optimize(3) // #pragma GCC optimize(4) #include <algorithm> #include <iterator> #include <iostream> #include <cstring> #include <cstdlib> #include <iomanip> #include <bitset> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <stack> #include <cmath> #include <queue> #include <list> #include <map> #include <set> #include <cassert> // #include<bits/extc++.h> // using namespace __gnu_pbds; using namespace std; #define pb push_back #define fi first #define se second #define debug(x) cerr<<#x << " := " << x << endl; #define bug cerr<<"-----------------------"<<endl; #define FOR(a, b, c) for(int a = b; a <= c; ++ a) typedef long long ll; typedef long double ld; typedef pair<int, int> pii; typedef pair<ll, ll> pll; const int inf = 0x3f3f3f3f; const ll inff = 0x3f3f3f3f3f3f3f3f; const int mod = 998244353; template<typename T> inline T read(T&x){ x=0;int f=0;char ch=getchar(); while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x=f?-x:x; } /**********showtime************/ const int maxn = 5e3+9; int a[maxn]; int col[maxn]; vector<int>L, R; vector<int>mp[maxn]; void dfs(int s, int c) { col[s] = c; for(int i=0; i<mp[s].size(); i++){ int v = mp[s][i]; if(col[v] == 0) dfs(v, 3 - c); } } int vis[maxn],match[maxn],pt[maxn]; bool gkd(int u) { if(vis[u]) return false; vis[u] = true; for(int i = 0; i<mp[u].size(); i++) { int v = mp[u][i]; if(match[v] == -1 || gkd(match[v]) ){ match[v] = u; pt[u] = v; return true; } } return false; } int res[maxn]; bool findmn(int u) { if(u == -1) return false; if(res[u]) return true; // res[u] = 1; if(col[u] == 1){ if(findmn(pt[u])) {res[u] = 1;return true;} else return false; } else { res[u] = 1; for(int i=0; i<mp[u].size(); i++) { int v = mp[u][i]; if(match[u] == v) continue; findmn(v); } return true; } } int main(){ int n; scanf("%d", &n); for(int i=1; i<=n; i++) scanf("%d", &a[i]); for(int i=1; i<=n; i++) { for(int j=i+1; j<=n; j++) { if(__builtin_popcount(a[i] ^ a[j]) == 1) { mp[i].pb(j); mp[j].pb(i); } } } for(int i=1; i<=n; i++) if(col[i] == 0) dfs(i, 1); int cnt = 0; memset(match, -1, sizeof(match)); for(int i=1; i<=n; i++) { memset(vis, 0, sizeof(vis)); if(col[i] == 1 && gkd(i)) cnt++; } printf("%d\n", n-cnt); for(int i=1; i<=n; i++) { if(col[i] == 2 && match[i] == -1) {findmn(i);} } vector<int>ans; for(int i=1; i<=n; i++) { if(col[i] == 1 && res[i] == 0) ans.pb(a[i]); if(col[i] == 2 && res[i] == 1) ans.pb(a[i]); } for(int i=0; i<ans.size(); i++) { printf("%d ", ans[i]); } puts(""); return 0; }
G subsequence 1
题意
给定两个数字字符串s,t。求一个数字字符串s中包含多少非连续子序列e,e在数位上大于t。
思路:
长度大于t的用组合数直接算。
等于t的我们利用动态规划dp[i][j],表示s的长度为i的前缀中有多少子序列大于t的长度为j的前缀。
// #pragma GCC optimize(2) // #pragma GCC optimize(3) // #pragma GCC optimize(4) #include <algorithm> #include <iterator> #include <iostream> #include <cstring> #include <cstdlib> #include <iomanip> #include <bitset> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <stack> #include <cmath> #include <queue> #include <list> #include <map> #include <set> #include <cassert> // #include<bits/extc++.h> // using namespace __gnu_pbds; using namespace std; #define pb push_back #define fi first #define se second #define debug(x) cerr<<#x << " := " << x << endl; #define bug cerr<<"-----------------------"<<endl; #define FOR(a, b, c) for(int a = b; a <= c; ++ a) typedef long long ll; typedef long double ld; typedef pair<int, int> pii; typedef pair<ll, ll> pll; const int inf = 0x3f3f3f3f; const ll inff = 0x3f3f3f3f3f3f3f3f; const int mod = 998244353; template<typename T> inline T read(T&x){ x=0;int f=0;char ch=getchar(); while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x=f?-x:x; } /**********showtime************/ const int maxn = 3e3+9; char s[maxn],t[maxn]; ll f[maxn][maxn]; ll C (int n, int m) { if(m > n) return 0; if(f[n][m]) return f[n][m]; if(m == 0||m == n) return f[n][m] = 1; return f[n][m] = (C(n-1, m-1) + C(n-1,m) ) %mod; } ll dp[maxn][maxn]; int main(){ int T; scanf("%d", &T); while(T--) { int n,m; scanf("%d%d", &n, &m); scanf("%s%s", s + 1, t + 1); ll ans = 0; for(int i=1; i<=n; i++) { if(s[i] == '0') continue; int yu = n - i; for(int j = m; j<=yu; j++) ans = (ans + C(yu, j)) % mod; } for(int i=0; i<=n; i++) dp[i][0] = 1; for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) { dp[i][j] = dp[i-1][j]; if(s[i] == t[j]) { dp[i][j] = (dp[i-1][j-1] + dp[i][j])% mod; } else if(s[i] > t[j]) { ans = (ans + dp[i-1][j-1] * C(n-i , m-j) % mod)% mod; } } } printf("%lld\n", ans); for(int i=0; i<=n; i++){ for(int j=0; j<=m; j++) dp[i][j] = 0; } } return 0; }
skr