首页 > 其他分享 >洛谷3281数数

洛谷3281数数

时间:2023-10-31 15:12:02浏览次数:36  
标签:子串 ... 数数 洛谷 前缀 cdot Pow overline 3281

这一道题给我们最大的启示就是一定要学会固定数字!

设\(Pow[i]=B^i\),\(f[i]=\sum_{k=0}^{i}{B^k}\)

\(h[i]\)表示所有\(i\)位数字的所有前缀子串的和

比如\(123456\)一共有\(6\)位,他的所有前缀子串为\(1,12,123,1234,12345,123456\),他的所有前缀子串和就是这六个数加起来,那么\(h[6]\)就表示\(100000,100001,……,999999\)所有这些数字的前缀子串和的和

我们求\(h[i]\)时,考虑最高位填什么。此时最高位在变换(可以从\(0\)一直到\(B\)),而剩下的数字也在变换(可以从\(\underbrace{00...0}_{\text{i-1个0}}\)一直到\(\underbrace{99...9}_{\text{i-1个9}}\)),我们就不好讨论,所以先固定假设我们已经选择了最高位的数字,这个数字为\(j\),剩下位的数字为\(\overline{abc...}\)

那么此时的所以前缀为\(\overline{j},\overline{ja},\overline{jab}...\),他们分别可以表示成\(j,j\cdot Pow[1]+a,j\cdot Pow[2]+a\cdot Pow[1]+b...\),所以这一个已经固定的数字的所有前缀和就是\(j\cdot f[i-1]\)+(\(\overline{abc...}\)这个数字的所有前缀子串和)

此时我们再假设\(j\)固定,\(\overline{abc...}\)在变化,再求一个和(即当最高位为\(j\)时,对\(h[i]\)的贡献),则为\(j\cdot f[i-1]\cdot Pow[i-1]+h[i-1]\)(注意一共有\(Pow[i-1]\)个数)

然后我们再假设\(j\)也在变换,再求一个和,则有$$h[i]=((\sum_{j=0}^{B-1}j)\cdot f[i-1]\cdot Pow[i-1])+B\cdot h[i-1]$$

以上过程完全可以先固定\(\overline{abc...}\),假设\(j\)在变化,然后假设\(\overline{abc...}\)在变化,答案是一模一样的

设\(g[i]\)表示所有\(i\)位数字的所有子串的和,用以上同样的方法可以得出$$g[i]=B\cdot g[i-1]+h[i]$$

然后试填的过程见以下代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+10;
const ll p=20130427;
int n,a[N];
ll f[N],g[N],h[N],Pow[N],B;
void prework()
{
	f[0]=1;
	Pow[0]=1;
	for(int i=1;i<=N-10;i++)
	{
		Pow[i]=Pow[i-1]*B%p;
		f[i]=(f[i-1]+Pow[i])%p;
		h[i]=(((B-1)*B>>1)%p*f[i-1]%p*Pow[i-1]%p+B*h[i-1]%p)%p;
		g[i]=(B*g[i-1]%p+h[i])%p;
	}
}
ll work()
{
	ll sum=0,val=0,res=0;
	//sum表示已经填了的数字的所有子串的和
	//val表示已经填了的数字的所有前缀子串的和
	//rse表示结果 
	for(int i=n;i>=2;i--) 
	for(int j=1;j<B;j++)
	{
		res=(res+g[n-i]+h[n-i])%p;
		res=(res+(j*Pow[n-i]%p*f[n-i]%p))%p;
	}
	//这个循环是在填写只有1位,2位...i-1位的情况
	//注意不能直接填写最高位的0
	//因为此时会导致重复计算
	//比如n=3,数字为095
	//那么本来应该只算9,5,95这三个子串的
	//但如果直接从最高位的0开始算
	//就会算成0,9,5,09,95,095
	//显然重复了 
	for(int i=1;i<a[1];i++)
	{
		res=(res+g[n-1])%p;
		res=(res+(i*Pow[n-1]%p*f[n-1]%p+h[n-1])%p)%p;
	}
	//考虑最高位的写法 
	val=a[1],sum=a[1];
	for(int i=2;i<=n;i++)
	{
		for(int j=0;j<a[i];j++)
		{
			res=(res+g[n-i])%p;
			ll temp=(val*B%p+(ll)j*i%p)%p;
			res=(res+(temp*Pow[n-i]%p*f[n-i]%p+i*h[n-i])%p)%p;
			res=(res+sum*Pow[n-i]%p)%p;
		}
		val=(val*B%p+(ll)a[i]*i%p)%p;
		sum=(sum+val)%p;
	}
	//可以用博客讲的方法推一下上面代码的式子 
	return (res+sum)%p;
	//注意还要在加上sum
	//因为要计算这个数本身的贡献 
}
int main()
{
	scanf("%lld",&B);
	prework();
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	int j=n;
	while(!a[j]) 
	{
		a[j]=B-1;
		j--;
	}
	a[j]--;
	if(j==1&&!a[j]) 
	{
		n--;
		for(int i=1;i<=n;i++) a[i]=B-1;
	}
	ll res1=work();
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	ll res2=work();
	printf("%lld",(res2-res1+p)%p);
    return 0;
}

以上代码肯定会超时,但是这个优化太简单了,具体见洛谷的提交

标签:子串,...,数数,洛谷,前缀,cdot,Pow,overline,3281
From: https://www.cnblogs.com/dingxingdi/p/17800272.html

相关文章

  • 【洛谷 8649】 [蓝桥杯 2017 省 B] k 倍区间
    题目描述给定一个长度为 �N 的数列,�1,�2,⋯��A1​,A2​,⋯AN​,如果其中一段连续的子序列 ��,��+1,⋯��(�≤�)Ai​,Ai+1​,⋯Aj​(i≤j) 之和是 �K 的倍数,我们就称这个区间 [�,�][i,j] 是 �K 倍区间。你能求出数列中总共有多少个 �K 倍区间吗?输入格式第一行包含两个整数 �N 和 �K......
  • 【洛谷 8742】[蓝桥杯 2021 省 AB] 砝码称重
    题目描述你有一架天平和 �N 个砝码,这 �N 个砝码重量依次是 �1,�2,⋯ ,��W1​,W2​,⋯,WN​ 。请你计算一共可以称出多少种不同的重量?注意砝码可以放在天平两边。输入格式输入的第一行包含一个整数 �N 。第二行包含 �N 个整数: �1,�2,�3,⋯ ,��W1​,W2​,W3​,⋯,WN​......
  • 【洛谷 2347】[NOIP1996 提高组] 砝码称重
    题目描述设有 1g1g、2g2g、3g3g、5g5g、10g10g、20g20g 的砝码各若干枚(其总重≤1000≤1000),可以表示成多少种重量?输入格式输入方式:�1,�2,�3,�4,�5,�6a1​,a2​,a3​,a4​,a5​,a6​(表示 1g1g 砝码有 �1a1​ 个,2g2g 砝码有 �2a2​ 个,…,20g20g 砝码有 �6a6​ 个)输出格式......
  • 【洛谷 8601】 [蓝桥杯 2013 省 A] 剪格子
    #[蓝桥杯2013省A]剪格子##题目描述如图$1$所示,$3\times3$的格子中填写了一些整数。![](https://cdn.luogu.com.cn/upload/image_hosting/hsfjsi38.png)我们沿着图中的红色线剪开,得到两个部分,每个部分的数字和都是$60$。本题的要求就是请你编程判定:对给定的$m\tim......
  • 洛谷P5706 【深基2.例8】再分肥宅水(Python3)
    关键点:1.同一行输入两个数input().split(),然后list一下存到变量里,这个不多说2。输出两个数Python中默认end=‘\n’,所以不用多写一遍换行。3.输出三位小数这里用到了Python的格式化输出,与c++的格式化输出非常相近,只是符号不同。具体可看这篇blog 代码如下:a=list(input(......
  • 洛谷 最长最短单词 c语言 函数解决
    #include<stdio.h>#include<string.h>inti;intmain(){intIs_letters(chara);//声明判断字母intbigword(charstr[]);//声明最长单词intminword(charstr[]);//声明最短单词charstr[20010];//str要足够大intt;gets(str);t......
  • 洛谷5597复读
    具体题解可以看zhy136036那一篇解释一下是如何合并树的每次都可以提取出来一个子树然后把这三棵子树重叠在一起(根对根,2号点对2号点,以此类推),就得到了这个新图然后解释一下为什么这么做是对的首先在单次操作中,至少需要把这个新树给遍历完,不然的话就会存在有些点遍历不到,即这是......
  • 洛谷-P9779 题解
    正文对于每个选择题,都有两种状态,因此总状态数为\(2^n\)。请注意初始所有选择题都不选也是一个状态,不计入贡献,因此答案为\(2^n-1\)。代码:#include<iostream>usingnamespacestd;intmain(){longlongn;cin>>n;cout<<(1<<n)-1;}提交记录。......
  • 洛谷题解 | AT_abc321_c Primes on Interval
    目录题目翻译题目描述输入格式输出格式样例#1样例输入#1样例输出#1样例#2样例输入#2样例输出#2样例#3样例输入#3样例输出#3题目简化题目思路AC代码题目翻译【题目描述】你决定用素数定理来做一个调查.众所周知,素数又被称为质数,其含义就是除了数字一和本身之外不能......
  • 洛谷 P2568 GCD
    题意:给定\(n\)求\(\displaystyle{\sum_{i=1}^n{\sum_{j=1}^n{\left[(i,j)\inprime\right]}}}\)其中\(prime\)为素数集合。\(n<10^7\)解:原式等于\[\displaystyle{\sum_{p\inprime}\sum_{i=1}^n{\sum_{j=1}^n{\left[(i,j)=p\right]}}}\]这等于\[\displa......