首页 > 其他分享 >AtCoder WTF 2019 B Multiple of Nine/南外集训 2024.2.23 T1

AtCoder WTF 2019 B Multiple of Nine/南外集训 2024.2.23 T1

时间:2024-02-23 13:12:57浏览次数:28  
标签:begin AtCoder 2024.2 Multiple int LL pos co MOD

给定 \(q\) 个区间 \(\{[l_i, r_i]\}\),计算满足条件的长度为 \(n\) 的十进制数码串 \(S\) 的个数 \(\bmod 10^9+7\):

  • \(\forall i \in [1,q], num(S[l_i, r_i]) \equiv 0\pmod 9\)。

其中 \(num(T)\) 表示数码串 \(T\) 代表的整数,\(T[a, b]\) 表示子串 \(T_aT_{a+1}\dots T_b\)。在这道题中,我们允许任意形式的前导零。

\(1\le q\le 15, 1\le n\le 10^9\)。

所有涉及到的前缀和位置和 \(0\) 位置是关键位置,我们关心它们的前缀和 \(\bmod 9\) 的结果。假设我们已经知道了这些结果,且满足题中条件,考虑有多少种合法序列符合它。此时可以计算两个相邻的关键位置之间的位置的填法数:假设这两个位置间隔 \(d\),则它们填出来的数有 \(\frac{10^d-1}{9}\) 种可能性 \(\bmod 9 = x\in[1,8]\),而有 \(\frac{10^d-1}{9}+1\) 种可能性 \(\bmod 9 = 0\)。所以我们只关心这两个关键位置的前缀和 \(\bmod 9\) 是否相等。我们先用并查集合并题中给出的区间对应的关键位置,这样只剩下 \(\le q+1\) 个块,接下来再去处理这些块的可能的相等关系。

先计算出所有相邻关键位置前缀和都不同时的答案,然后计算出如果存在某个极大等价类,那么它会让答案乘以多少,这可以用 \(\Theta(q2^q)\) 得到。接下来使用相等关系容斥(实际上就是集合幂级数取 \(\ln\)),得到钦定一个等价类存在的权值,这一部分可以用某些集合幂级数技术做到 \(\Theta(q^22^q)\),但是直接 \(\Theta(3^n)\) 也行。最后进行集合划分 DP,复杂度依然是 \(\Theta(q^22^q)\) 或 \(\Theta(3^q)\)。注意到我们似乎把 \(0\) 位置搞进来了,所以最后需要除以 \(9\),表示 \(0\) 位置的这个连通块前缀和必须被钦定成 \(0\)。还要算上最后一段没被覆盖到的部分,这些位置显然可以任意填。

// Author: kyEEcccccc

#include <bits/stdc++.h>

using namespace std;

using LL = long long;
using ULL = unsigned long long;

#define F(i, l, r) for (int i = (l); i <= (r); ++i)
#define FF(i, r, l) for (int i = (r); i >= (l); --i)
#define MAX(a, b) ((a) = max(a, b))
#define MIN(a, b) ((a) = min(a, b))
#define SZ(a) ((int)((a).size()) - 1)

constexpr int N = 16, MOD = 1000000007;

LL kpow(LL x, ULL k = MOD-2)
{
	x = x % MOD;
	LL r = 1;
	while (k)
	{
		if (k & 1) r = r * x % MOD;
		x = x * x % MOD;
		k >>= 1;
	}
	return r;
}

int len, n;
int a[N], b[N];
vector<int> pos;
int ff[N*2], co[N*2], tot_co;
LL tar[1 << N], coef[1 << N], f[1 << N];

int get_anc(int x)
{
	if (x == ff[x]) return x;
	return ff[x] = get_anc(ff[x]);
}

signed main(void)
{
	freopen("string.in", "r", stdin);
	freopen("string.out", "w", stdout);
	ios::sync_with_stdio(0), cin.tie(nullptr);

	cin >> len >> n;
	pos.assign(1, 0);
	F(i, 0, n-1) cin >> a[i] >> b[i], --a[i], pos.push_back(a[i]), pos.push_back(b[i]);
	sort(pos.begin(), pos.end());
	pos.erase(unique(pos.begin(), pos.end()), pos.end());
	F(i, 0, n-1)
	{
		a[i] = lower_bound(pos.begin(), pos.end(), a[i]) - pos.begin();
		b[i] = lower_bound(pos.begin(), pos.end(), b[i]) - pos.begin();
	}
	F(i, 0, SZ(pos)) ff[i] = i;
	F(i, 0, n-1) ff[get_anc(b[i])] = get_anc(a[i]);
	F(i, 0, SZ(pos)) if (ff[i] == i) co[i] = tot_co++;
	F(i, 0, SZ(pos)) co[i] = co[get_anc(i)];
	assert(tot_co <= N);

	LL xx = 1;
	F(i, 1, SZ(pos))
	{
		int d = pos[i] - pos[i-1];
		LL x = (kpow(10, d) - 1) * kpow(9) % MOD;
		(xx *= x) %= MOD;
	}
	F(w, 1, (1<<tot_co)-1)
	{
		tar[w] = 1;
		F(i, 1, SZ(pos))
		{
			if (!((w >> co[i] & 1) && (w >> co[i-1] & 1))) continue;
			int d = pos[i] - pos[i-1];
			LL x = (kpow(10, d) - 1) * kpow(9) % MOD;
			(tar[w] *= kpow(x) * (x+1) % MOD) %= MOD;
		}
		// cerr << w << ' ' << tar[w] << '\n';
		coef[w] = tar[w];
		int u = __lg(w&-w);
		for (int ww = w^1<<u; ww; ww = (ww - 1) & (w^1<<u))
		{
			(coef[w] -= tar[ww] * coef[w^ww]) %= MOD;
			(f[w] += f[ww] * coef[w^ww] % MOD * 9) %= MOD;
		}
		(f[w] += coef[w] * 9) %= MOD;
	}
	LL ans = f[(1<<tot_co)-1] * xx % MOD * kpow(10, len - pos.back()) % MOD * kpow(9);
	cout << (ans % MOD + MOD) % MOD << '\n';
	
	return 0;
}

标签:begin,AtCoder,2024.2,Multiple,int,LL,pos,co,MOD
From: https://www.cnblogs.com/kyeecccccc/p/18029275

相关文章

  • 2024.2.22 初三集训模拟测试4
    终于挽回了一点颜面。(模拟赛最水的一集)排名T1打赌不得语,暗相思,两心之外无人知。一直记录这骰子的上面、正面和右面。先把暴力打出来,然后优化一下就行。同一行翻转的时候一直是四个状态循环,随便处理一下就行。一顾倾城,再顾倾国。#include<bits/stdc++.h>#definein......
  • 2024.2.22 梦想 在什么地方 总是那么令人向往
    字符串太难了。今天早上起来牙又疼了,很难受。UOJ461考虑当前已经把整张图分成了\(L,R\)两个点集,考虑extend一个点进来。可以使用二分的方式,具体的将未加入的点按任意顺序排列,二分一个前缀并断掉\(L,R\)与这个前缀的所有边,找到一个最小的前缀满足此时不连通,此时对于这个......
  • 2024.2.22模拟赛T3 题解
    对于区间连边,可以线段树优化建图对于单点连边,可以使用李超线段树维护迪杰斯特拉code#include<bits/stdc++.h>usingnamespacestd;#defineN400005#defineintlonglong#definepiipair<int,int>#definefirfirst#definesecsecondintn,m,tot;intval[N];const......
  • 2024.2.22 LGJ Round
    A你需要求\(n\timesm\)格子里随机撒\(k\)个点,期望扫多少次使得相邻的格子没有同时有点。\(n\timesm\le80,k\le20\)。直接状压求出方案数即可。B你需要维护一个数组,支持区间求和或执行覆盖操作fori:=ltordoa[i]:=a[i-k]或区间回溯成一开始的数。可持久化平衡......
  • 龙哥盟 Python 译文集 2024.2 更新
    每个程序员都应该知道的40个算法Python数学应用Python入门指南Python物联网入门指南Python比特币编程实用指南Python密码学实用指南Python数据结构和算法实用指南Python企业自动化实用指南PythonGPU编程实用指南Python物联网项目LearningScrapy中文版通......
  • 山海经&&Atcoder Alternating String (线段树)
    前言:为什么把他们放在一起?因为我发现把pushup向上回溯放结构体类型函数里比较方便并且这两题确实也有相同思想山海经这题分三种情况左子树前缀和+右子树前缀和2.右子树后缀和与右总区间+左子树3.左区间最大子段与右区间最大子段与左后缀与右前缀特别要注意......
  • 2024.2.21 まぁ、この世の中ガチャの引き次第で 何もかも説明つくわけだし?
    模拟赛不知道对于\(d(n)\)很大的数可以做根号质因数分解,直接输完了。中午在外面吃饭,去了一家很有创意和技术的餐馆,西安菜还是有辣的,而且还挺不错。晚上看RMR,A队进了,小蜜蜂能不能进呢,不知道。跳跃DP形式形如高维偏序,于是考虑怎么样来做这个东西。常规做法有点菜,考虑高维......
  • 2024.2 做题记录
    省流:因为一月底回厦门玩然后又回泉州过年,直到2.17才开始做题。[APIO2018]铁人两项圆方树和后缀数组我都想开个贴单独写。考虑关于“简单路径”,在点双上都有很特殊的性质。考虑把原图的圆方树建出来,然后考虑简单路径和圆方树的关系。注意到,在同一点双的两点的简单路径的并集,......
  • 2024.2.21游记
    首先,文对于线段\([A,B]\),\([C,D]\)什么时候相交。\(B\)为\(A\)的祖先,\(D\)为\(C\)的祖先相交有一种情况,在\([A,B]\)上有一个分叉,连接\(C\),然后分叉上面为\(D\),这是候,就会发现\(B\)是\(C\)的祖先,\(D\)是\(A\)的祖先代码形式LCA(B,......
  • Solution Set【2024.2.21】
    [ARC162C]MexGameonTree可以发现若Bob在某个节点填了值\(K\),那么会直接导致其根链上的所有节点均不可能满足要求。因此若某个节点的子树内有不小于两个空位,那么Alice一定无法使该子树满足要求。若某节点子树内有一个空位且可以通过填上这一空位使其合法,那么Alice可......