Round G 2019 - Kick Start 2019
Posted 163467wyj
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Round G 2019 - Kick Start 2019相关的知识,希望对你有一定的参考价值。
https://codingcompetitions.withgoogle.com/kickstart/round/0000000000050e02/000000000018fd0d
Book Reading (10pts, 15pts)
1 ≤ T ≤ 100.
1 ≤ P1 < P2 < ... < PM ≤ N.
1 ≤ Ri ≤ N, for all i.
Test set 1 (Visible)
1 ≤ M ≤ N ≤ 1000.
1 ≤ Q ≤ 1000.
Test set 2 (Hidden)
1 ≤ M ≤ N ≤ 105.
1 ≤ Q ≤ 105.
题意:一本书有 1……n页,撕去 p 页,有 q 个读者, 问读者一共能阅读的页数
如果直接枚举暴力的话, 10ps 到手
#include<bits/stdc++.h> using namespace std; #define _for(i,a,b) for(int i = (a); i < (b); i++) #define _rep(i,a,b) for(int i = (a); i <= (b); i++) const int N = 1e5+100; int a[N],b[N],vis[N]; int main(){ ios::sync_with_stdio(0); cin.tie(0); int t,n,m,q,kase = 1; cin >>t ; while(t--) { cin >> n >> m >> q; int x,cnt = 0; memset(vis, 0, sizeof(vis)); _for(i,0,m) cin >> x, vis[x] = 3; _for(i,0,q) { cin >> x; for(int j = x; j <= n; j += x) if(vis[j] != 3) cnt++; } cout << "Case #"<< kase++ << ": "; cout << cnt << endl; } return 0; }
但是很明显, 会 TLE, 所以需要优化下
#include<bits/stdc++.h> using namespace std; #define _for(i,a,b) for(int i = (a); i < (b); i++) #define _rep(i,a,b) for(int i = (a); i <= (b); i++) #define ll long long const int N = 1e5+100; int main(){ ios::sync_with_stdio(0); cin.tie(0); int t,n,m,q,kase = 1; cin >>t ; while(t--) { vector<int> a(N, 0); vector<bool> vis(N, false); cin >> n >> m >> q; int x; ll cnt = 0; _for(i,0,m) cin >> x, vis[x] = true; _for(i,0,q) { cin >> x; if(a[x]){ cnt += a[x]; continue; } for(int j = x; j <= n; j += x) if(!vis[j]) a[x]++; cnt += a[x]; } cout << "Case #"<< kase++ << ": "; cout << cnt << endl; } return 0; }
https://codingcompetitions.withgoogle.com/kickstart/round/0000000000050e02/000000000018fe36
The Equation (12pts, 20pts)
直接暴力 12pts可到手
#include<bits/stdc++.h> using namespace std; const double eps = 1e-10; const double pi = 3.1415926535897932384626433832795; const double eln = 2.718281828459045235360287471352; #define scld(x) scanf("%lld", &x) #define prcas printf("Case #%d: ", cas) #define pncas printf("Case #%d: ", cas) #define lowbit(x) ((x) & (-(x))) #define fi first #define se second typedef long long LL; typedef unsigned long long ull; typedef pair<int, int> pii; typedef pair<LL, LL> pll; typedef vector<int> vi; const int maxn = 25; int dp[1048550]; LL a[maxn], b[maxn]; int n, T, h; int main() { scanf("%d", &T); for(int cas = 1; cas <= T; ++ cas) { scanf("%d %d", &n, &h); for(int i = 0; i < n; ++ i) scld(a[i]); //for(int i = 0; i < n; ++ i) scld(b[i]); prcas; int flag = 0; for(int i = 128; i >= 0; i--){ int sum = 0; for(int j = 0; j < n; j++) sum += a[j]^i; if(sum <= h) { flag = 1; printf("%d ", i);break; } } if(!flag) printf("-1 "); } return 0; }
通过对 k 的二进制位数进行枚举, cnt[i][0] cnt[i][1]分别记录 数组a的 第i+1位的 0 与 1的个数
再通过 ret[i][0] ret[i][1] 分别表示对前 i 位的a数组的 0 与 1 表示的和
然后 通过 suf[i] 记录前 i 项 min(ret[i][0], ret[i][1])的和, (???)
然后枚举 位数 i 51~0 如果符合 ret[i][1]+suf[i-1] k |= 1<<i , 即 k 的这个二进制位为 1, 否则为 0 m-= ( 为1 ? ret[i][1] : ret[i][0])
若枚举结束 m < 0, 则不存在 k
#include<bits/stdc++.h> using namespace std; const double eps = 1e-10; const double pi = 3.1415926535897932384626433832795; #ifdef __LOCAL_DEBUG__ # define _debug(fmt, ...) fprintf(stderr, "[%s] " fmt " ", __func__, ##__VA_ARGS__) #else # define _debug(...) ((void) 0) #endif #define IN freopen("B.in", "r", stdin) #define OUT freopen("B.out", "w", stdout) #define scd(x) scanf("%d", &x) #define scld(x) scanf("%lld", &x) #define scs(x) scanf("%s", x) #define mp make_pair #define pb push_back #define sqr(x) (x) * (x) #define prcas printf("Case #%d: ", cas) #define pncas printf("Case #%d: ", cas) #define lowbit(x) ((x) & (-(x))) #define fi first #define se second typedef long long LL; typedef unsigned long long ull; typedef pair<int, int> pii; typedef pair<LL, LL> pll; typedef vector<int> vi; const int maxk = 51; int cnt[65][2]; int n, T; LL m, ans, ret[65][2], suf[65]; int main() { scd(T); for(int cas = 1; cas <= T; ++ cas) { for(int i = 0; i <= maxk; ++ i) cnt[i][0] = cnt[i][1] = 0; scanf("%d%lld", &n, &m); while(n --) { LL x; scanf("%lld", &x); ans = 0; for(int i = 0; i <= maxk; ++ i, x >>= 1) cnt[i][x & 1] ++; } for(int i = 0; i <= maxk; ++ i) ret[i][0] = 1ll * cnt[i][1] * (1ll << i), ret[i][1] = 1ll * cnt[i][0] * (1ll << i); suf[0] = min(ret[0][0], ret[0][1]); for(int i = 1; i <= maxk; ++ i) suf[i] = suf[i - 1] + min(ret[i][0], ret[i][1]); for(int i = maxk; i >= 0 && m >= 0; -- i) { LL t = 0; if(i > 0) t = suf[i - 1]; if(ret[i][1] + t <= m) { ans |= 1ll << i; m -= ret[i][1]; }else m -= ret[i][0]; } if(m < 0) ans = -1; prcas; printf("%lld ", ans); } return 0; } /* Input 4 3 27 8 2 4 4 45 30 0 4 11 1 0 100 6 2 5 5 1 5 1 0 Case #1: 12 Case #2: 14 Case #3: 100 Case #4: -1 */
https://codingcompetitions.withgoogle.com/kickstart/round/0000000000050e02/000000000018fd5e
Shifts (20pts, 23pts)
题意:有n个班次, h 快乐值要求, 问有多少种情况 a 与 b 都快乐(快乐值大于等于h)
如果直接暴力的话, 0~ 3^n-1, 暴力枚举 每个班次的三种情况(单选a, 单选b, 同时选ab),n<=12,5e5的样子,能过 Test set 1, 但Test set 2 3e8(n<=20)就会TLE
TLE
#include<bits/stdc++.h> using namespace std; #define rep(x,y) for(long long i =x;i<=y;i++) #define pb push_back #define mp make_pair #define ALL(x) (x).begin(),(x).end() #define FastIO ios_base::sync_with_stdio(false); cin.tie(NULL); typedef long long ll; typedef pair< ll, ll> pll; typedef vector< ll > vll; typedef map < ll, ll > mll; int main() { ll i,j,t,test,ans,n,num,s1,s2,a[30],b[30],h,ways; test=1; cin >> t; while(t--) { cout << "Case #" << test << ": " ; ans=0; test++; cin >> n >> h; rep(1,n) cin >> a[i]; rep(1,n) cin >> b[i]; ways= pow(3,n)-1; rep(0,ways) { num=i; j=1; s1=0; s2=0; while(j<=n) { if(num%3==0) { s1+=a[j]; } else if(num%3==1) s2+=b[j]; else { s1+=a[j]; s2+=b[j]; } num/=3; j++; } // cout << s1 << " " << s2 << endl; if(s1>=h && s2>=h) ans++; } cout << ans << endl; } return 0; }
dp[mask] mask 0~2^n-1, 以0 1 分 n个a是否被取
then mask 0~2^n-1 i 0~n dp[mask^(1<<i)] += dp[mask]
then x 0~2^n-1 dp[x] 2^n-x-1(二进制01 代表n个b是否被取) 神奇的穷举操作
最后会发现 所有的可能 3^n 都被枚举了
比如说 n = 2,
a b
dp[0] = 00 01 10 11 11
dp[1] = 01 11 10
dp[2] = 10 11 01
dp[3] = 11 00
#include<bits/stdc++.h> using namespace std; const double eps = 1e-10; const double pi = 3.1415926535897932384626433832795; const double eln = 2.718281828459045235360287471352; #define scld(x) scanf("%lld", &x) #define prcas printf("Case #%d: ", cas) #define pncas printf("Case #%d: ", cas) #define lowbit(x) ((x) & (-(x))) #define fi first #define se second typedef long long LL; typedef unsigned long long ull; typedef pair<int, int> pii; typedef pair<LL, LL> pll; typedef vector<int> vi; const int maxn = 25; int dp[1048550]; LL a[maxn], b[maxn]; int n, T, h; int main() { scanf("%d", &T); for(int cas = 1; cas <= T; ++ cas) { scanf("%d %d", &n, &h); for(int i = 0; i < n; ++ i) scld(a[i]); for(int i = 0; i < n; ++ i) scld(b[i]); for(int mask = 0; mask < (1 << n); ++ mask) { LL sum = 0; for(int i = 0; i < n; ++ i) if((mask >> i) & 1) sum += a[i]; if(sum >= h) dp[mask] = 1; else dp[mask] = 0; } //for(int mask = 0; mask < (1 << n); ++ mask) printf("dp[%d]= %d ", mask, dp[mask]);printf(" "); for(int i = 0; i < n; ++ i) for(int mask = 0; mask < (1 << n); ++ mask) if((mask >> i) & 1) dp[mask ^ (1 << i)] += dp[mask]; LL ans = 0; //for(int mask = 0; mask < (1 << n); ++ mask) printf("dp[%d]= %d ", mask, dp[mask]);printf(" ... "); for(int mask = 0; mask < (1 << n); ++ mask) { LL sum = 0, task = 0; for(int i = 0; i < n; ++ i) if((mask >> i) & 1) sum += b[i]; else task |= (1 << i); if(sum < h) continue; ans += dp[task]; } prcas; printf("%lld ", ans); } return 0; }
以上是关于Round G 2019 - Kick Start 2019的主要内容,如果未能解决你的问题,请参考以下文章
DP 好题Kick Start 2019 Round C Catch Some
Kick Start 2019 - Round A A.Training 题解
Kick Start 2018-Round H-Problem B. Mural