2 条题解
-
1
题目说: 可以将其中相邻的值为0的段合并压缩起来
感觉有问题,因为最终答案应该是把只有一个零的情况也计算上了,也就是按照标准ipv6去压缩。
static final long MOD = (long) 1e9 + 7; private static void solve() { // System.out.println((1 << 4)); // System.out.println((1 << 4 * 2) - (1 << 4)); // System.out.println((1 << 4 * 3) - (1 << 4 * 2)); // System.out.println((1 << 4 * 4) - (1 << 4 * 3)); // System.out.println(65536); long[] a = {16, 240, 3840, 61440}; // 分别代表长度为1,2,3,4的次数 long res = 0; for (int i1 = 0; i1 < 4; i1++) for (int i2 = 0; i2 < 4; i2++) for (int i3 = 0; i3 < 4; i3++) for (int i4 = 0; i4 < 4; i4++) for (int i5 = 0; i5 < 4; i5++) for (int i6 = 0; i6 < 4; i6++) for (int i7 = 0; i7 < 4; i7++) for (int i8 = 0; i8 < 4; i8++) // 八位,每一位四种情况全部枚举 { long part = 1; part = part * a[i1] % MOD * a[i2] % MOD * a[i3] % MOD * a[i4] % MOD; part = part * a[i5] % MOD * a[i6] % MOD * a[i7] % MOD * a[i8] % MOD; part = part * (i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + 8 + 7) % MOD; res = (res + part) % MOD; // 上面的 +7 是(马嘉祺bushi)没去冒号的个数 } for (int i = 0; i < 256; i++) { String s = Integer.toBinaryString(i); // 转二进制 int len = maxLen(s); // System.out.println(" " + len); // 输出每一种的二进制最长要去的大小 if (len <= 0) continue; long part = len; for (int j = 0; j < s.length(); j++) // 枚举要去0的所有可能 { if (s.charAt(j) == '1') part = (part * 65535) % MOD; // 因为最大65536,去0这种可能就是65535 } res = (res + MOD - part) % MOD; } System.out.println(res); } private static int maxLen(String s) { int len = s.length(); for (int i = 0; i < 8 - len; i++) s = "0" + s; // System.out.print(s); // 输出每一种的二进制情况 String zero = "00000000"; for (int i = 8; i >= 1; i--) // 从大的开始暴力枚举每一个,判断字符串里面有没有 { int in = s.indexOf(zero.substring(0, i)); if (in + i >= s.length() && in == 0) return i * 2 - 3; // 0000-0000这种情况,要留2个冒号 else if (in + i >= s.length()) return i * 2 - 2; // 最大的在最后的情况,要留1个冒号 else if (in > 0) return i * 2 - 1; // 最大的在中间的情况,不用留冒号 else if (in == 0) // 最大的在前面的情况,还要判断相同大小在不在中间 { int inn = s.substring(1).indexOf(zero.substring(0, i)); if (inn != -1 && inn + i < s.length() - 1) return i * 2 - 1; // 最大的在中间和开头的情况,取最小不用留冒号的情况 else return i * 2 - 2; // 大的在最后和开头的情况,要留1个冒号 } } return 0; // 代表找不到0 }
-
1
考虑四维DP做法: 表示当前段、当前长度、当前能减少数量和末尾是否 '0' 结尾。
#include <bits/stdc++.h> using namespace std; #define int long long #define double long double #define endl "\n" // 预处理 char jz[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; int a[6]; int get(int x) { if (x == 0) return 1; int c = 0; while (x) c++, x /= 16; return c; } const int n = 8, m = 16 * 16 * 16 * 16, l = 40, mod = 1e9 + 7; int f[n + 1][2 * l + 1][l + 1][2]; // 当前段 当前长度 当前能减少数量 末尾0结尾 void solve() { for (int i = 1; i < m; i++) a[get(i)]++; f[0][0][0][0] = 1; for (int i = 1; i <= n; i++) // 当前下标 for (int id = 0; id < i; id++) // 先前下标 for (int j = 0; j <= l; j++) // 先前长度 for (int g = 0; g <= l; g++) // 先前减少 { for (int k = 1; k <= 4; k++) // 添加长度 { int c = i - id - 1; // id+1~i-1用0填充 i用非1填充 int del = max(0ll, c * 2 - 1 - (id == 0)); // 可以减少的长度 f[i][j + k + c + (i - max(id, 1ll))][max(del, g)][0] += f[id][j][g][0] * a[k]; f[i][j + k + c + (i - max(id, 1ll))][max(del, g)][0] %= mod; } int c = i - id; // id+1~i用0填充 int del = max(0ll, c * 2 - 1 - (id == 0) - (i == n)); // 可以减少的长度 f[i][j + c + (i - max(id, 1ll))][max(del, g)][1] += f[id][j][g][0]; f[i][j + c + (i - max(id, 1ll))][max(del, g)][1] %= mod; } int ans = 0; // 计算答案 for (int j = 0; j <= l; j++) for (int g = 0; g <= l; g++) for (int xy = 0; xy <= 1; xy++) { ans += f[8][j][g][xy] * (j - g); ans %= mod; } cout << ans << endl; } signed main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cout << fixed << setprecision(10); int t = 1; // cin >> t; while (t--) solve(); return 0; }
- 1
信息
- ID
- 36
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 7
- 已通过
- 3
- 上传者