XVII Open Cup named after E.V. Pankratiev. XXI Ural Championship
C.Construction sets 二分答案 多重背包二进制优化 bitset检验
#include<stdio.h> #include<iostream> #include<string.h> #include<string> #include<ctype.h> #include<math.h> #include<set> #include<map> #include<vector> #include<queue> #include<bitset> #include<algorithm> #include<time.h> using namespace std; void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); } #define MS(x, y) memset(x, y, sizeof(x)) #define ls o<<1 #define rs o<<1|1 typedef long long LL; typedef unsigned long long UL; typedef unsigned int UI; template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a) { a = b; } } template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a) { a = b; } } const int N = 55, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f; template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; } int casenum, casei; int n, mn, mx; int m[N], c[N]; bitset<10005>f; bool check(int K) { f.reset(); f[0] = 1; for (int i = 1; i <= n; ++i) { int tot = c[i] / K; int g = 1; LL v = m[i]; while (tot) { if (v > mx) { break; } f |= f << v; /*!!!! 等价于: for(int k=v;k<=10005;k++) f[k]|=f[k-v]; !!!!*/ /*cout << "i:" << i << endl; for (int i = 1; i <= mx; i++) { cout << f[i] << " "; } cout << endl;*/ tot -= g; //多重背包二进制优化 g = min(g * 2, tot); //多重背包二进制优化 v = (LL)m[i] * g; //多重背包二进制优化 } } for (int j = mn; j <= mx; ++j) { if (f[j]) { return 1; } } return 0; } int main() { //freopen("input.txt", "r", stdin); //freopen("output.txt", "w", stdout); while (~scanf("%d%d%d", &n, &mn, &mx)) { for (int i = 1; i <= n; ++i) { scanf("%d%d", &m[i], &c[i]); } int l = 0; int r = 1e6; while (l < r) { int mid = (l + r + 1) >> 1; //cout << "mid:" << mid << endl; if (check(mid)) { l = mid; } else { r = mid - 1; } } printf("%d\n", l); } return 0; }
D.Dinner party DP
#include<cstdio> #include<bitset> using namespace std; const int N = 1010, M = 2010; int T, n, m, i, j, x, y, cnt; bitset<M>f[N]; //!!!! f[i][j]表示面积为i周长为j(目标周长的一半)是否有可能 int f2[1050][2050]; void solve() { scanf("%d%d", &n, &m); if (m % 2) //!!!! 周长肯定是偶数 { puts("No"); return; } m /= 2; if (f[n][m] == 0) //!!!!不可能 { puts("No"); return; } puts("Yes"); int cnt = 0; static int q[100000][2]; while (n) { int X = 0, Y = 0; for (x = 1; x <= n; x++) { for (y = 1; y * x <= n; y++) if (x + y <= m) if (f[n - x * y][m - x - y]) { X = x, Y = y; break; } if (X) { break; } } q[++cnt][0] = X; q[cnt][1] = Y; n -= X * Y; m -= X + Y; } printf("%d\n", cnt); for (int i = 1; i <= cnt; i++) { printf("%d %d\n", q[i][0], q[i][1]); } } int main() { //freopen("input.txt", "r", stdin); //freopen("output.txt", "w", stdout); //scanf("%d%d",&n,&m); n = 1000; m = 2000; f[0][0] = 1; f2[0][0] = 1; for (i = 0; i <= n; i++) for (x = 1; x + i <= n; x++) for (y = 1; x * y + i <= n; y++) { f[i + x * y] |= f[i] << (x + y); /*!!!! 表示f[i+x*y] 与上 f[i]左移(乘上)x+y 等价于: for (int k = 0; k <= m - x - y; k++) { f2[i + x * y][k + x + y] |= f2[i][k]; } !!!!*/ } scanf("%d", &T); while (T--) { solve(); } }
G.Glasses with solutions 折半搜索 把35个拆成两半 复杂度为C(2,2)*2*2^(35/2)
#include<cstdio> #include<map> using namespace std; typedef long long ll; const int N=40; int n,m,A,B,i,x,y,a[N];map<ll,ll>f; ll ans; void dfsl(int x,ll y){ if(x==m){f[y]++;return;} dfsl(x+1,y+a[x]); dfsl(x+1,y); } void dfsr(int x,ll y){ if(x==n){ans+=f[-y];return;} dfsr(x+1,y+a[x]); dfsr(x+1,y); } int main(){ freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); scanf("%d%d%d",&n,&A,&B); for(i=0;i<n;i++){ scanf("%d%d",&x,&y); a[i]=x*B-A*y; } m=n/2; dfsl(0,0); dfsr(m,0); ans--; printf("%lld",ans); }
H. Hamburgers 二进制压缩&枚举操作
#include<cstdio> #include<cstring> #include<vector> using namespace std; const int N = 55555; int n, m, i, j, k, x, ans[N], mx[N], b[N]; vector<int>a[N]; bool v[(1 << 26) + 5]; inline int get() //!!!!二进制压缩 把每个人的口味压缩成1<<26内的数 { static char s[1000]; scanf("%s", s); int t = 0, len = strlen(s); for (int i = 0; i < len; i++) { t |= 1 << (s[i] - 'a'); //!!!!!!转换成二进制 } return t; } inline void make(int x, int y) { for (int i = x; i; i = (i - 1)&x) //!!!!枚举每位1存在或不存在的情况 { v[i] = y; } } int main() { //freopen("input.txt", "r", stdin); //freopen("output.txt", "w", stdout); scanf("%d", &n); for (i = 1; i <= n; i++) { scanf("%d", &k); while (k--) { x = get(); a[i].push_back(x); } ans[i] = 1; } scanf("%d", &m); for (i = 1; i <= m; i++) { scanf("%d", &k); for (j = 1; j <= k; j++) { b[j] = get(); } for (j = 1; j <= k; j++) { make(b[j], 1); //!!!找出每种情况 } for (j = 1; j <= n; j++) { int t = 0; for (x = 0; x < a[j].size(); x++) if (v[a[j][x]]) { t++; } if (t > mx[j]) { mx[j] = t, ans[j] = i;//!!!!找出每个group最适应的店 } } for (j = 1; j <= k; j++) { make(b[j], 0); //!!!相当于memset 把先前变为1的变回0 } } for (i = 1; i <= n; i++) { printf("%d\n", ans[i]); } }
J.Jumps through the Hyperspace 预处理+迪杰斯特拉
#include<cstdio> #include<algorithm> #include<vector> #include<queue> using namespace std; typedef pair<int, int>P; const int N = 2010, inf = ~0U >> 1; int n, m, st, i, j, a[N], b[N], c[N], d[N], w[N][N]; int f[N]; char g[N][N], op[N]; priority_queue<P, vector<P>, greater<P> >q; inline void ext(int x, int y) { if (f[x] > y) { q.push(P(f[x] = y, x)); } } int main() { //freopen("input.txt", "r", stdin); //freopen("output.txt", "w", stdout); scanf("%d%d%d", &n, &m, &st); while (m--) { scanf("%s", op); int o = op[0]; scanf("%d%d%d%d", &a[o], &b[o], &c[o], &d[o]); for (i = 0; i < c[o]; i++) //!!!i为到达时间即 到某k点的时间%c[k] { w[o][i] = inf; for (j = 0; j < c[o]; j++) //!!!j为等待时间 { w[o][i] = min(w[o][i], (a[o] * (i + j) + b[o]) % c[o] + d[o] + j); //!!!处理出每种到达时间最优旅行方法 } } } for (i = 1; i <= n; i++) { scanf("%s", g[i] + 1); } for (i = 1; i <= n; i++) { f[i] = inf; } ext(1, st); //!!!!把起点放入迪杰斯特拉优先队列 while (!q.empty()) { P t = q.top(); q.pop(); if (f[t.second] < t.first) { continue; } for (i = 1; i <= n; i++) if (g[t.second][i] != '.') //!!!有道路的话进行松弛操作 { ext(i, t.first + w[g[t.second][i]][t.first % c[g[t.second][i]]]);//!!!!松弛操作 } } if (f[n] == inf) { puts("-1"); } else { printf("%d", f[n] - st); } }