2 条题解

  • 1
    @ 2025-4-17 11:15:34

    题目说: 可以将其中相邻的值为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
      @ 2025-4-16 17:38:52

      考虑四维DP做法: fi,j,k,gf_{i,j,k,g} 表示当前段、当前长度、当前能减少数量和末尾是否 '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
      上传者