AtCoder Grand Contest 018 做题记录
来源:互联网 发布:mysql synonym 编辑:程序博客网 时间:2024/06/01 09:47
退役后的第一次补题
果然做题的时间拉长了好多
但是挺多题自己想出来了
也是蛮爽的
UPD:8.11 明早还要上课,能写多少写多少吧。
UPD:8.12 F留坑待填
A - Getting Difference
有点翻车,A想了好久才弄出来
题意:
有
- 拿出两个球上面分别写着
x ,y ,放回去三个球上面分别写着x ,y ,|x−y|
询问是否能在若干次操作后使得序列中存在球的值为
解答:
联系欧几里得算法,可以的得出进行若干次操作后,我们能得到的最小的数,是这些数的gcd。判断
时空复杂度:
#include <bits/stdc++.h>#define N 1000500using namespace std;inline int rd() { int x=0,f=1;char ch=getchar(); while (ch>'9'||ch<'0') {if(ch=='-')f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return x*f;}int n,k,mx,a[N];int main() { n = rd(), k = rd(); for (int _=1;_<=n;_++) a[_] = rd(), mx = max(mx, a[_]); int g = a[1]; for (int _=2;_<=n;_++) g = __gcd(g, a[_]); if (k <= mx && (mx-k)%g == 0) puts("POSSIBLE"); else puts("IMPOSSIBLE"); return 0;}
B - Sports Festival
题意:
有
每个人有一个
作为主办方,你现在要选取一些运动,举办这些运动的比赛。
运动员会参加被举办的运动中,自己最喜欢的那一个运动参加。
你需要选出一些运动,使得举办这些运动时,参加人数最多的那一项运动参赛人数最少,输出这个人数。
解答:
不妨先选取所有的运动。
考虑目前参赛人数最多的运动
所以我们每次删去参赛人数最多的运动,然后对于每一个人分别统计答案。
时空复杂度:
#include <bits/stdc++.h>#define N 305using namespace std;inline int rd() { int x=0,f=1;char ch=getchar(); while (ch>'9'||ch<'0') {if(ch=='-')f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return x*f;}int n,m,a[N][N],vis[N],cnt[N];int main() { n = rd(), m = rd(); for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) a[i][j] = rd(); for (int i=1;i<=m;i++) vis[i] = 1; int ans = n; for (int _=1;_<=m;_++) { memset(cnt,0,sizeof(cnt)); for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) if (vis[ a[i][j] ]) { cnt[ a[i][j] ]++; break; } int mx = 0, id = 0; for (int i=1;i<=m;i++) if (cnt[i] >= mx) mx = cnt[i], id = i; ans = min(ans, mx); vis[id] = 0; } printf("%d\n",ans); return 0;}
C - Coins
题意:
现在有
每个人只能给你三种硬币中的一种,你需要指定
求能得到硬币的最大值。
解答:
令
考虑
此时我们可以按照
当
那么序列中显然存在一个或多个位置,使得在这个位置之前的所有元素选择
爆枚这个位置,用堆维护元素的差值,算出在
时间复杂度:
#include <bits/stdc++.h>#define N 200050using namespace std;typedef long long LL;inline int rd() { int x=0,f=1;char ch=getchar(); while (ch>'9'||ch<'0') {if(ch=='-')f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return x*f;}struct HbFS{int a,b,c;}Q[N];bool cmp(HbFS p1, HbFS p2) {return p1.a-p1.b > p2.a-p2.b;}priority_queue<int, vector<int>, greater<int> > q1,q2;int x,y,z,n;LL L[N],R[N];int main() { x = rd(), y = rd(), z = rd(); n = x + y + z; for (int _=1;_<=n;_++) Q[_].a = rd(), Q[_].b = rd(), Q[_].c = rd(); sort(Q+1,Q+n+1,cmp); for (int _=1;_<=x;_++) q1.push(Q[_].a - Q[_].c), L[_] = L[_-1] + Q[_].a; for (int _=x+1;_<=n;_++) { int cur = Q[_].a - Q[_].c; L[_] = L[_-1]; if (cur > q1.top()) { int tmp = q1.top(); q1.pop(); q1.push(cur); L[_] -= tmp; L[_] += Q[_].a; } else L[_] += Q[_].c; } for (int _=n;_>=n-y+1;_--) q2.push(Q[_].b - Q[_].c), R[_] = R[_+1] + Q[_].b; for (int _=n-y;_>=1;_--) { int cur = Q[_].b - Q[_].c; R[_] = R[_+1]; if (cur > q2.top()) { int tmp = q2.top(); q2.pop(); q2.push(cur); R[_] -= tmp; R[_] += Q[_].b; } else R[_] += Q[_].c; } LL ans = 0LL; for (int _=x;_<=n-y;_++) ans = max(ans, L[_]+R[_+1]); cout << ans << endl; return 0;}
D - Tree and Hamilton Path
题意:
给定一个
给定的图是一棵树
读入的数都是整数
解答:
一条边最后贡献答案的次数,至多是两倍拿掉该条边后的两个连通块中较小的那个连通块大小,记这个值为
由子树大小,联想到树的重心,分两种情况。
树的重心,即树上的一个点,使得拿掉这个点之后树上最大连通块的大小
- 树只存在一个重心。这条哈密尔顿路径的两端至少有一端不为该树的重心,则重心到连向该点所在子树的根这一条边是无法达到它所能经过最多次数的上限的。若令哈密尔顿路径起点为重心,终点为该子树的根,是可以构造一条合法的哈密尔顿路径达到另外所有边的上限的。(即在各个子树间来回跳)。选取一条连接重心权值最小的边的两端作为起点和终点即可。
最终答案为S−min( 连接重心的一条边的边权$) - 树存在两个重心。连接这两个重心的那一条边,至多可以经过
n−1 次。(同样考虑哈密尔顿路径的起点和终点),同样我们以这条边的两个端点分别作为哈密尔顿路径的起点和终点,在两个子树间来回跳即可达到最大值。
最终答案为S−( 连接两个重心那条边的权值)
综上所述,即重心一定要作为哈密尔顿路径的起点或者终点。
通过树上
#include <bits/stdc++.h>#define N 1000500using namespace std;typedef long long LL;inline int rd() {int r;scanf("%d",&r);return r;}struct Edge{int b,v,n;}e[2*N];int siz[N],h[N],cnt,mark,g,n;LL ans;void link(int a,int b,int v) { e[++cnt] = (Edge){b,v,h[a]}, h[a] = cnt;}void dfs(int u,int f,int p) { siz[u] = 1; int mx = 0; for (int i=h[u];i;i=e[i].n) { int v = e[i].b, cp = e[i].v; if (v == f) continue; dfs(v, u, cp); siz[u] += siz[v]; mx = max(mx, siz[v]); } mx = max(mx, n-siz[u]); if (siz[u]*2 == n) mark = p; if (mx*2 <= n) g = u; ans += 2LL * p * min(siz[u], n-siz[u]);}int main() { n = rd(); for (int i=1;i<n;i++) { int a = rd(), b = rd(), c = rd(); link(a, b, c); link(b, a, c); } dfs(1,1,0); if (!mark) { mark = 2147483647; for (int i=h[g];i;i=e[i].n) mark = min(e[i].v, mark); } cout << ans - mark << endl; return 0;}
E - Sightseeing Plan
题意:
给定一个网格图,你需要制定一个旅行计划:
- 起点的横坐标在区间
[X1,X2] ,纵坐标在区间[Y1,Y2] - 途径一个特殊点,横坐标在区间
[X3,X4] , 纵坐标在区间[Y3,Y4] - 终点的横坐标在区间
[X5,X6] ,纵坐标在区间[Y5,Y6]
求有多少条不同的最短路。
两条路径是不同的,当且仅当路径的起点不同,选择的特殊点不同,终点不同,或者途径的点不同。答案对
解答:
这题有点恶心,真的再也不想见到这种题。
定义
有
利用:
可以得出:
类比二维前缀和,可以将起点的区域转化成四个带权的单点
+1 : (x2+1,y2+1), (x1,y1)
-1 : (x1,y2+1), (x2+1,y1)
同理,也可以将终点的区域转化成四个带权的单点
原问题可以转化成求16个固定起点和终点,在固定区域
考虑这条路径进入固定区域的点以及离开固定区域的点,原问题路径按照进入固定区域的点和离开固定区域的点分类,最后答案乘上在固定区域内行走的路径长度,即为所求。
时空复杂度为
#include <bits/stdc++.h>#define mod 1000000007#define N 2000500using namespace std;typedef long long LL;LL Fac[N],Inv[N],Iac[N];int x[7],y[7];inline int rd() { int x=0,f=1;char ch=getchar(); while (ch>'9'||ch<'0') {if(ch=='-')f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return x*f;}inline void inc(LL &x,LL y) {x=(x+y)%mod;}inline LL C(int x,int y) { return 1LL * Fac[x+y] * Iac[x] % mod * Iac[y] % mod;}inline LL W(int x1,int y1,int x2,int y2) { x1 = abs(x1); y1=abs(y1); x2=abs(x2); y2=abs(y2); return (1LL *C(x2+1,y2+1) - C(x2+1,y1) - C(x1,y2+1) + C(x1,y1)+mod + mod) % mod;}void init() { for (int i=1;i<=6;i++) x[i] = rd(); for (int i=1;i<=6;i++) y[i] = rd();}void prepare() { int n = 2000000; Fac[0] = Fac[1] = 1; for (int i=2;i<=n;i++) Fac[i] = 1LL * Fac[i-1] * i % mod; Inv[0] = Inv[1] = 1; for (int i=2;i<=n;i++) Inv[i] = 1LL * (mod - mod / i) * Inv[mod%i] % mod; Iac[0] = Iac[1] = 1; for (int i=2;i<=n;i++) Iac[i] = 1LL * Iac[i-1] * Inv[i] % mod;}void solve() { LL ans = 0LL; for (int _=x[3];_<=x[4];_++) inc(ans, 1LL*(mod-_-y[3])*W(_-x[2],y[3]-1-y[2],_-x[1],y[3]-1-y[1])%mod * W(_-x[5],y[3]-y[5],_-x[6],y[3]-y[6])%mod); for (int _=x[3];_<=x[4]; _++) inc(ans, 1LL*(_+y[4]+1)*W(_-x[2],y[4]-y[2],_-x[1],y[4]-y[1])%mod*W(_-x[5],y[4]-y[5]+1,_-x[6],y[4]-y[6]+1)%mod); for (int _=y[3];_<=y[4];_++) inc(ans, 1LL*(mod-_-x[3])*W(x[3]-1-x[2],_-y[2],x[3]-1-x[1],_-y[1])%mod *W(x[3]-x[5], _-y[5], x[3]-x[6], _-y[6])%mod); for (int _=y[3];_<=y[4];_++) inc(ans, 1LL*(_+x[4]+1)*W(x[4]-x[2],_-y[2],x[4]-x[1],_-y[1])%mod *W(x[4]-x[5]+1,_-y[5],x[4]-x[6]+1,_-y[6])%mod); cout<<ans<<endl;}int main() { init(); prepare(); solve(); return 0;}
F留坑待填
- AtCoder Grand Contest 018 做题记录
- AtCoder Grand Contest 014做题记录
- AtCoder Grand Contest 016做题记录
- AtCoder Grand Contest 017做题记录
- AtCoder Grand Contest 018
- AtCoder Grand Contest 018
- AtCoder Grand Contest 018 A
- atcoder grand Contest 018 A
- AtCoder Grand Contest 018 A
- AtCoder Grand Contest 018 E
- AtCoder Grand Contest 018 F
- 【AtCoder】 Grand Contest 018 C
- AtCoder Grand Contest 018 --------- Getting Difference
- AtCoder Grand Contest 018--D题
- AtCoder Grand Contest 010
- AtCoder Grand Contest 011
- Atcoder Grand Contest 019
- AtCoder Grand Contest 010
- 矩阵快速幂
- 快速排序算法
- java 为什么InputStream.read()读取一个byte却返回一个int呢?
- Java集合-01之 总体框架
- 继续xxx定律
- AtCoder Grand Contest 018 做题记录
- JZOJ 5258. 友好数对
- Effective Modern C++翻译系列之Item18
- JAVA——线程中start()和run()的区别
- 线程中fork函数的使用
- 斜率优化(待更)
- Java并发包--ReentrantLock
- Keras实现卷积神经网络
- 远程桌面按键失效变成快捷键问题