首页 > 其他分享 >「杂题乱刷2」P3107

「杂题乱刷2」P3107

时间:2024-07-25 10:50:49浏览次数:18  
标签:last forl sum len P3107 杂题 ll define

题目链接

P3107 [USACO14OPEN] Odometer S

解题思路

数位 dp 模板。

令某个数的特殊数字在一个数字中至少出现过一半的数位的数字

首先我们可以依次拆分数位来枚举当某个数位为特殊数字时来进行数位 dp,状态为 \(dp_{last,len,num,sum,\_1,\_0}\) 来代表还剩余 \(last\) 个数位需要处理,当前去除先导零时的当前数字的位数为 \(len\),当前的特殊数字为 \(num\),当前出现的特殊数字的次数为 \(sum\),\(\_1\) 表示当前的位数是否取满,\(\_0\) 表示当前数字是否当前取的数字不全为零。

但是这样是不对的,为什么呢?你会发现,可能会有 \(114414\) 这样类型的数字,这种数字会分别在以 \(1\) 为特殊数字时被计算一次,以 \(4\) 为特殊数字时计算一次,你会发现,这个数字对答案的贡献被重复计算了

然后我们可以发现,一个数字会被重复计算当且仅当:

  • 这个数字有两种不同的数位。

  • 这个数字出现过的两种数位的出现次数相等。

这个部分也是数位 dp 板子。

状态为 \(dp_{last,len,num1,num2,sum1,sum2,\_1,\_0}\) 来代表还剩余 \(last\) 个数位需要处理,当前去除先导零时的当前数字的位数为 \(len\),当前的特殊数字 \(1\) 为 \(num1\),当前的特殊数字 \(2\) 为 \(num2\),当前出现的特殊数字 \(1\) 次数为 \(sum\),当前出现的特殊数字 \(2\) 次数为 \(sum2\),\(\_1\) 表示当前的位数是否取满,\(\_0\) 表示当前数字是否当前取的数字不全为零。

与前面的答案简单容斥一下即可。

参考代码

点击查看代码
#include<bits/stdc++.h>
using namespace std;
//#define map unordered_map
#define re register
#define ll long long
#define forl(i,a,b) for(re ll i=a;i<=b;i++)
#define forr(i,a,b) for(re ll i=a;i>=b;i--)
#define forll(i,a,b,c) for(re ll i=a;i<=b;i+=c)
#define forrr(i,a,b,c) for(re ll i=a;i>=b;i-=c)
#define mid ((l+r)>>1)
#define lowbit(x) (x&-x)
#define pb push_back
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
#define endl '\n'
#define QwQ return 0;
#define db long double
#define ull unsigned long long
#define lcm(x,y) x/__gcd(x,y)*y
#define Sum(x,y) 1ll*(x+y)*(y-x+1)/2
#define aty cout<<"Yes\n";
#define atn cout<<"No\n";
#define cfy cout<<"YES\n";
#define cfn cout<<"NO\n";
#define xxy cout<<"yes\n";
#define xxn cout<<"no\n";
#define printcf(x) x?cout<<"YES\n":cout<<"NO\n";
#define printat(x) x?cout<<"Yes\n":cout<<"No\n";
#define printxx(x) x?cout<<"yes\n":cout<<"no\n";
#define maxqueue priority_queue<ll>
#define minqueue priority_queue<ll,vector<ll>,greater<ll>>
void Max(ll&x,ll y){x=max(x,y);}
void Min(ll&x,ll y){x=min(x,y);}
ll t;
ll l,r;
ll a[20],k;
ll dp[20][20][15][20][2][2];
int dp2[20][20][10][10][10][10][2][2];
__int128 ans;
ll dfs(ll last,ll len,ll num,ll sum,ll _1,ll _0)
{
	if(last==0)
		return sum*2>=len && sum && len && _0;
	if(dp[last][len][num][sum][_1][_0]>=0)
		return dp[last][len][num][sum][_1][_0];
	ll maxn=_1?a[last]:9,ans=0;
	forl(i,0,maxn)
		ans+=dfs(last-1,len+(_0||(i!=0)),num,sum+(i==num && (_0 || (i!=0))),_1&&(i==maxn),_0||(i!=0));
	dp[last][len][num][sum][_1][_0]=ans;
	return ans;
}
ll dfs2(ll last,ll len,ll num,ll num2,ll sum,ll sum2,ll _1,ll _0)
{
	Min(sum,9ll),Min(sum2,9ll);
	if(last==0)
		return sum+sum2==len && sum && len && _0 && sum2 && sum==sum2;
	if(dp2[last][len][num][num2][sum][sum2][_1][_0]>=0)
		return dp2[last][len][num][num2][sum][sum2][_1][_0];
	ll maxn=_1?a[last]:9,ans=0;
	forl(i,0,maxn)
		ans+=dfs2(last-1,len+(_0||(i!=0)),num,num2,sum+(i==num && (_0 || (i!=0))),sum2+(i==num2 && (_0 || (i!=0))),_1&&(i==maxn),_0||(i!=0));
	dp2[last][len][num][num2][sum][sum2][_1][_0]=ans;
	return ans;
}
ll sol(ll x,ll y)
{
	k=0;
	while(x)
		a[++k]=x%10,x/=10;

	return dfs(k,0,y,0,1,0);
}
ll sol2(ll x,ll y,ll z)
{
	k=0;
	while(x)
		a[++k]=x%10,x/=10;
	return dfs2(k,0,y,z,0,0,1,0);
}
void solve()
{
	forl(i,0,19)
		forl(j,0,19)
			forl(ii,0,14)
				forl(jj,0,19)
					forl(iii,0,1)
						forl(jjj,0,1)
							dp[i][j][ii][jj][iii][jjj]=-1;
	forl(i,0,19)
		forl(j,0,19)
			forl(ii,0,9)
				forl(jj,0,9)
					forl(iii,0,9)
						forl(jjj,0,9)
							forl(iiii,0,1)
								forl(jjjj,0,1)
									dp2[i][j][ii][jj][iii][jjj][iiii][jjjj]=-1;
	cin>>l>>r;
	forl(i,0,9)
		ans+=sol(r,i);
	forl(i,0,19)
		forl(j,0,19)
			forl(ii,0,14)
				forl(jj,0,19)
					forl(iii,0,1)
						forl(jjj,0,1)
							dp[i][j][ii][jj][iii][jjj]=-1;
	forl(i,0,9)
		ans-=sol(l-1,i);
	forl(i,0,9)
		forl(j,i+1,9)
			ans-=sol2(r,i,j);
	forl(i,0,19)
		forl(j,0,19)
			forl(ii,0,9)
				forl(jj,0,9)
					forl(iii,0,9)
						forl(jjj,0,9)
							forl(iiii,0,1)
								forl(jjjj,0,1)
									dp2[i][j][ii][jj][iii][jjj][iiii][jjjj]=-1;
	forl(i,0,9)
		forl(j,i+1,9)
			ans+=sol2(l-1,i,j);
	ll an=ans;
	cout<<an<<endl;
}
int main()
{
	IOS;
	t=1;
// 	cin>>t;
	while(t--)
		solve();
	QwQ;
}

标签:last,forl,sum,len,P3107,杂题,ll,define
From: https://www.cnblogs.com/wangmarui/p/18322520

相关文章

  • 2024 暑假集训杂题选做
    目录写在前面CF1981DCF1992F写在最后写在前面我是飞物。CF1981D2400妈的好诡异的题场上拿到这题我都不知道我要干啥呃呃考虑到每个合数均为若干质数的乘积,则若构造方案中有合数,可以将合数替换为质数从而减少使用的权值的种类数,于是仅需考虑使用质数构造,则此时并不需要考虑具......
  • 「杂题乱刷2」CF1615C Menorah
    题目链接CF1615CMenorah(luogu)CF1615CMenorah(codeforces)解题思路这题有三个重要的性质:在同一个点做两次操作与不在这个点做操作是等价的。给两个不同的点做操作等价于交换这两个点。给一个字符串做偶数次操作,这个字符串的\(0\)的数量和\(1\)的数量不会改......
  • 「杂题乱刷2」CF1015D Walking Between Houses
    duel到的。题目链接CF1015DWalkingBetweenHouses解题思路一道细节题。思路很简单,肯定是一开始能走的越多越好,因此就有一种较好实现的方案,先每次走\(n-1\)格,但由于每次至少要走一格,因此如果不够走了就把能走的都走掉,之后全走\(1\)步即可。时间复杂度\(O(k)\)。参......
  • 「杂题乱刷2」CF727D
    duel到的。题目链接CF727D解题思路首先只能选一个尺码的人直接给就是了,这样我们就只用考虑选两个尺码的人了。因为两个尺码的人适合的两个尺码是相邻的,因此我们直接从小到大按照有两个尺码的人排序,再将剩下的衣服大小从小到大排序,然后依次给就可以了。这里我用了桶排,时间复......
  • 「杂题乱刷2」CF1506E Restoring the Permutation
    duel到的。题目链接CF1506E解题思路有一个显然的性质就是这个序列的前缀最大值是单调不降的。于是我们就可以对于每个位置考虑还可以填哪些数,对于字典序最小的肯定填当时可填的最小数字,对于字典序最大的肯定填当时可填的最大数字,因为你可以通过填一个数的方式来满足要求,因此......
  • Spark Special_杨宁远 杂题分析.md
    SparkSpecial图论_杨宁远杂题分析Date:2024-07-03Preface本文基于杨宁远@ynycoding的课件与题单,对省选/NOIP阶段图论的建模方法和解题策略进行总结,以及本阶段常用方法、模型和Trick。A.[AGC056C]0/1Balanced[AGC056C]01Balanced-洛谷|计算机科学教育新生态(......
  • 「杂题乱刷2」CF402D Upgrading Array
    题目链接CF402DUpgradingArray(luogu)CF402DUpgradingArray解题思路首先有一个很显然的结论,就是你一旦在第\(i\)个位置上做了一次操作后,那么你之后所有在第\(j(i\lej)\)个位置做的操作都无效了,因为此时前缀的公因数为\(1\)了。因此有个很显然的结论就是操作需要......
  • 「杂题乱刷2」CF1454F Array Partition
    题目链接CF1454FArrayPartition解题思路我们发现显然第一个和第三个区间的值区间随着长度的增大而增大。于是我们就可以枚举第一个区间的右端点位置,然后现在问题就转化成了找到一个断点来确定第二,三个区间的长度,由于前文提到的第三个区间的值区间随着长度的增大而增大,于是我......
  • 24.7 杂题
    时隔一年啊,不会复建、、、[HNOI2012]与非这个\(\operatorname{NAND}\)实际上可以做出任何位运算操作。而所有的位运算有一个性质,就是说如果两个位一样,那么操作完还是一样的。如果全部\(a\)中这些位置都相同,那么最后理应也相同。也就是假设对于所有\(n\)个\(a\),这两个位......
  • 2024.7.5杂题选讲
    前情提要:题解尽可能的写详细了,但是有些证明写着太费时间就没写了喵本来\(pyb\)想让我弄一个数据结构专题,结果发现我前阵子做的那些列表里的题,每一个的提交记录里都有\(jsy\),很多题里有\(xcy\)。。。实在整不出什么花活了,太菜了没做啥大家都没做过的题qwq,完全的水题选讲关注Luo......