A.Trails and Glades(未完成)
B.Two Sets(赛后完成)
题意:题目给n个数字,询问能否将n个数字分入两个集合A、B。
对于集合A,X和a - X 同属于 集合A。
对于集合B,X和b - X 同属于 集合B。
思路:A!=B时,
反向思考,如果 a - X 不存在 , 那么 X 只能放入 B 集合中 (假定集合成立)
如果 b - X 不存在 , 那么 X 只能放入 A 集合中 (假定集合成立)
将 n + 1 作为 集合A 的根节点 , 将 n + 2 作为 集合B 的根节点
1.
如果 a - X 不存在 , bset(X ,n + 2);将 X 并入 集合B 中
如果 b - X 不存在 , bset(X ,n + 1);将 X 并入 集合A 中
2.
如果 a - X 存在 ,则将 X 和 a - X 合并起来,但是不代表 X 和 a - X 属于集合A
如果 a - X 存在 , b - X 不存在 , 将 X 并入 集合A 中
3.
如果 a - X 存在 并且 b - X 存在 , 则说明 X 需要同时属于 集合A 和 集合B , 肯定不符合题目要求
如果 a - X 不存在 并且 b - X 不存在 , 则说明 X 需要同时不属于 集合A 和 集合B , 肯定不符合题目要求
当所求集合满足题目条件的时候 , 集合A 的祖先 和 集合B 的祖先 必然不同
相反 , 当集合A的祖先和集合B祖先相同时,题目条件必定不成立
A==B时
只要满足n个数字都属于其中一个集合即可。
那么只要 X 和 a - X都存在 , 那么必定可以将n个数字放入其中一个集合
#include<cstdio> #include<string.h> #include<algorithm> #include<cmath> #include<iostream> #include<vector> #include<queue> #include<set> #include<stack> #include<map> #include<cctype> #define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) #define mem(a,x) memset(a,x,sizeof(a)) #define lson rt<<1,l,mid #define rson rt<<1|1,mid + 1,r #define P pair<int, int> #define ull unsigned long long using namespace std; typedef long long ll; const int maxn = 1e6 + 10; const ll mod = 998244353; const int inf = 0x3f3f3f3f; const long long INF = 0x3f3f3f3f3f3f3f3f; const double eps = 1e-7; ll GCD(ll a, ll b) { while (b ^= a ^= b ^= a %= b); return a; } ll LCM(ll a, ll b) { return a * b / GCD(a, b); } ll prime[maxn] = { 0 }, num_prime = 0; int isNotPrime[maxn] = { 1 , 1 }; inline ll read() { ll X = 0, w = 0; char ch = 0; while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); } while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar(); return w ? -X : X; } inline void write(int x) { if (x < 0) putchar('-'), x = -x; if (x > 9) write(x / 10); putchar(x % 10 + '0'); } void isPrime() { for (int i = 2; i < maxn; ++i) { if (!isNotPrime[i]) prime[num_prime++] = i; for (int j = 0; j < num_prime && i * prime[j] < maxn; ++j) { isNotPrime[i * prime[j]] = 1; if (!i % prime[j]) break; } } printf("%lld", prime[num_prime - 1]); } ll binaryPow(ll a, ll b, ll c) { ll ans = 1; while (b > 0) { if (b & 1) { ans = ans * a % c; } a = a * a % c; b >>= 1; } return ans % c; } void BUG() { printf("DEBUG\n"); } ll n, a, b; ll arr[maxn]; map<ll, ll>mp; int f[maxn]; int find(int x) { return x == f[x] ? x : f[x] = find(f[x]); } void bset(int x, int y) { int fx = find(x); int fy = find(y); f[fx] = fy; } int main() { scanf("%lld %lld %lld", &n, &a, &b); for (int i = 1; i <= n + 2; ++i) f[i] = i; for (int i = 1; i <= n; ++i) { scanf("%lld", &arr[i]); mp[arr[i]] = i; } for (int i = 1; i <= n; ++i) { if (mp.count(a - arr[i])) bset(i, mp[a - arr[i]]); else bset(i, n + 2); if (mp.count(b - arr[i])) bset(i, mp[b - arr[i]]); else bset(i, n + 1); } if (find(n + 1) == find(n + 2)) { printf("NO\n"); } else { printf("YES\n"); for (int i = 1; i <= n; ++i) { if (find(i) == find(n + 1)) printf("0"); else printf("1"); if (i == n) printf("\n"); else printf(" "); } } return 0; }
C.Destroying Array(赛后完成)
题意:给出n个数字ai , 再给出n个数字表示销毁n个数据的顺序 , 询问每次消除数据之后,序列中最大的区间和是多少
思路:反向思维
将消除数据,转变为依次添加数据,并求出序列中最大的区间和
每次添加数据a[pos] ,并将 并查集 a[pos - 1] 和 a[pos + 1] 合并到 a[pos] 中 来更新区间和 ,通过与上一次最大区间和进行比较获取本次最大区间和
#include<cstdio> #include<string.h> #include<algorithm> #include<cmath> #include<iostream> #include<vector> #include<queue> #include<set> #include<stack> #include<map> #include<cctype> #define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) #define mem(a,x) memset(a,x,sizeof(a)) #define lson rt<<1,l,mid #define rson rt<<1|1,mid + 1,r #define P pair<int, int> #define ull unsigned long long using namespace std; typedef long long ll; const int maxn = 1e6 + 10; const ll mod = 998244353; const int inf = 0x3f3f3f3f; const long long INF = 0x3f3f3f3f3f3f3f3f; const double eps = 1e-7; ll GCD(ll a, ll b) { while (b ^= a ^= b ^= a %= b); return a; } ll LCM(ll a, ll b) { return a * b / GCD(a, b); } ll prime[maxn] = { 0 }, num_prime = 0; int isNotPrime[maxn] = { 1 , 1 }; inline ll read() { ll X = 0, w = 0; char ch = 0; while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); } while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar(); return w ? -X : X; } inline void write(int x) { if (x < 0) putchar('-'), x = -x; if (x > 9) write(x / 10); putchar(x % 10 + '0'); } void isPrime() { for (int i = 2; i < maxn; ++i) { if (!isNotPrime[i]) prime[num_prime++] = i; for (int j = 0; j < num_prime && i * prime[j] < maxn; ++j) { isNotPrime[i * prime[j]] = 1; if (!i % prime[j]) break; } } printf("%lld", prime[num_prime - 1]); } ll binaryPow(ll a, ll b, ll c) { ll ans = 1; while (b > 0) { if (b & 1) { ans = ans * a % c; } a = a * a % c; b >>= 1; } return ans % c; } void BUG() { printf("DEBUG\n"); } ll brr[maxn]; ll n, m; ll arr[maxn]; ll ans[maxn]; ll crr[maxn]; ll f[maxn]; ll visit[maxn]; int find(int x) { return x == f[x] ? x : f[x] = find(f[x]); } void bset(int x, int y) { int fx = find(x), fy = find(y); f[fx] = fy; } int main() { scanf("%lld", &n); for (int i = 0; i <= 2 * n; ++i) { f[i] = i; crr[i] = 0; visit[i] = 0; } for (int i = 1; i <= n; ++i) { scanf("%lld", &arr[i]); } for (int i = n; i >= 1; --i) { scanf("%lld", &brr[i]); } ans[0] = 0; for (int i = 1; i <= n; ++i) { ll pos = brr[i]; visit[pos] = 1; ll l = pos - 1; ll r = pos + 1; ll tmp = arr[pos]; if (visit[l] != 0 && l >= 1) { l = find(l); tmp += crr[l]; bset(l, pos); } if (visit[r] != 0 && r <= n) { r = find(r); tmp += crr[r]; bset(r, pos); } crr[pos] = tmp; ans[i] = max(ans[i - 1], tmp); } for (int i = n - 1; i >= 0; --i) { printf("%lld\n", ans[i]); } return 0; }
D.Chemical table(未完成)
E.Gourmet choice(未完成)
F.The LCMs Must be Large(未完成)
G.Zjnu Stadium(赛后完成)
题意:有n个节点,m个询问,询问存在 ans 个 询问为假 (和之前给出的询问所得到的条件相冲突)
思路:带权并查集模板题
#include<cstdio> #include<string.h> #include<algorithm> #include<cmath> #include<iostream> #include<vector> #include<queue> #include<set> #include<stack> #include<map> #include<cctype> #define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) #define mem(a,x) memset(a,x,sizeof(a)) #define lson rt<<1,l,mid #define rson rt<<1|1,mid + 1,r #define P pair<int, int> #define ull unsigned long long using namespace std; typedef long long ll; const int maxn = 1e6 + 10; const ll mod = 998244353; const int inf = 0x3f3f3f3f; const long long INF = 0x3f3f3f3f3f3f3f3f; const double eps = 1e-7; ll GCD(ll a, ll b) { while (b ^= a ^= b ^= a %= b); return a; } ll LCM(ll a, ll b) { return a * b / GCD(a, b); } ll prime[maxn] = { 0 }, num_prime = 0; int isNotPrime[maxn] = { 1 , 1 }; inline ll read() { ll X = 0, w = 0; char ch = 0; while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); } while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar(); return w ? -X : X; } inline void write(int x) { if (x < 0) putchar('-'), x = -x; if (x > 9) write(x / 10); putchar(x % 10 + '0'); } void isPrime() { for (int i = 2; i < maxn; ++i) { if (!isNotPrime[i]) prime[num_prime++] = i; for (int j = 0; j < num_prime && i * prime[j] < maxn; ++j) { isNotPrime[i * prime[j]] = 1; if (!i % prime[j]) break; } } printf("%lld", prime[num_prime - 1]); } ll binaryPow(ll a, ll b, ll c) { ll ans = 1; while (b > 0) { if (b & 1) { ans = ans * a % c; } a = a * a % c; b >>= 1; } return ans % c; } void BUG() { printf("DEBUG\n"); } ll value[maxn]; ll f[maxn]; ll ans = 0; int find(int x) { if (x != f[x]) { int t = f[x]; f[x] = find(f[x]); value[x] += value[t]; } return f[x]; } void bset(int x, int y ,int v) { int fx = find(x); int fy = find(y); if (fx != fy) { f[fx] = fy; value[fx] = value[y] - value[x] + v; } else { if (value[x] - value[y] != v) { ans++; } } } int main() { int n, m; while (~scanf("%d %d",&n,&m)) { ans = 0; for (int i = 1; i <= n; ++i) { f[i] = i; value[i] = 0; } for (int i = 1; i <= m; ++i) { int a, b, c; scanf("%d %d %d", &a, &b, &c); bset(a, b ,c); } cout << ans << endl; } return 0; }
一个从很久以前就开始做的梦。