[6.27~7.4 做题记录]

news/2024/7/7 13:44:41/文章来源:https://www.cnblogs.com/lty-ylzsx/p/18285023

[6.27~7.4 做题记录]

暑假集训,记录一些有意义 (多半无意义) 题目,不定时更新。

概率期望DP

OSU!

考虑设 \(E_i\) 为到第 \(i\) 次操作时的期望分数。我们发现从 \(x^3\)\((x+1)^3\) 将加上 \(3x^2+3x+1\),我们考虑 \(x\)\(x^2\) 的期望:

\[x1_i=(x1_{i-1}+1)\times p_i \]

\[x2_i=(x2_{i-1}+2\times x1_{i-1}+1)\times p_i \]

为什么呢,对于 \(x1\),有 \(p_i\) 的概率增加 \(1\)\(x2\) 同理。

那么就有:

\[E_i=E_{i-1}+(3\times x2_{i-1}+3\times x1_{i-1}+1)\times p_i \]

for(int i=1;i<=n;i++){x1[i]=(x1[i-1]+1)*p[i];x2[i]=(x2[i-1]+2*x1[i-1]+1)*p[i];E[i]=E[i-1]+(3*x2[i-1]+3*x1[i-1]+1)*p[i];
}
printf("%.1lf",E[n]);

灯灯灯

逆天推式子数奥题。

\(n\) 盏红灯,\(m\) 盏绿灯,考虑先假设剩下的是红灯,然后绿灯同理。

  • 设剩下 \(k\) 盏红灯,那么剩下的第 \(k+1\) 盏一定为绿灯,那么只有前 \(n+m-k-1\) 盏灯是不确定的,其中有 \(n-k\) 盏红灯,\(m-1\) 盏绿灯,这 \(n+m-k-1\) 盏灯的顺序为 \(\tbinom{n+m-k-1}{n-k}\),而这所有的 \(n+m\) 盏灯有 \(\tbinom{n+m}{n}\) 种顺序,因此剩下 \(k\) 盏红灯的概率为 \(\dfrac{\binom{n+m-k-1}{n-k}}{\binom{n+m}{n}}\)
  • 那么,剩下红灯的期望为:

\[E= \sum _{k=1}^n \dfrac{\dbinom{n+m-k-1}{n-k}\times k}{\dbinom{n+m}{n}} = \dfrac{\sum \limits _{k=1}^n \dbinom{n+m-k-1}{n-k}\times k}{\dbinom{n+m}{n}} \]

  • 考虑化简上式,我们主要利用了两个等式:

    1. \(\tbinom{n}{m}=\tbinom{n-1}{m}+\tbinom{n-1}{m-1}\)
    2. \(\tbinom{n}{0}=\tbinom{n+1}{0}=\tbinom{n-1}{0}\)
  • 分子化简:

    \[= \tbinom{n+m-2}{n-1}\times 1+\tbinom{n+m-3}{n-2}\times 2+\tbinom{n+m-4}{n-3}\times 3 +\dots+\tbinom{n+m-n}{n-n+1}\times (n-1)+\tbinom{n+m-n-1}{n-n}\times n \]

    • 我们发现上式类似一个三角形,最后是 \(\tbinom{m}{1}\times (n-1)+\tbinom{m-1}{0}\times n\)
    • 由式2得 \(\tbinom{m}{1}\times (n-1)+\tbinom{m}{0}\times n\),再由式1得 \(\tbinom{m+1}{1}\times (n-1)+\tbinom{m}{0}\),接着再加上 \(\tbinom{m+1}{2}\times (n-2)\),可得 \(\tbinom{m+2}{2}\times (n-2)+\tbinom{m+1}{1}+\tbinom{m}{0}\)
    • 以此类推,逐层消消消,最后得到 \(\tbinom{m+n-1}{n-1}+\tbinom{m+n-2}{n-2}+\dots+\tbinom{m+2}{2}+\tbinom{m+1}{1}+\tbinom{m}{0}\)
    • 接着,我们由式2得到 \(\tbinom{m}{0}=\tbinom{m+1}{0}\),再用式1一个一个消,不再赘述。消完就是 \(\tbinom{m+n-1}{n}\)
  • 最终得到结果为 \(\dfrac{\dbinom{m+n}{n-1}}{\dbinom{m+n}{n}}=\dfrac{n}{m+1}\)

  • 最后剩下的绿灯同理,即为 \(\dfrac{m}{n+1}\)

  • 答案即 \(\dfrac{n}{m+1}+\dfrac{m}{n+1}\)

double ans=1.0*n/(m+1)+1.0*m/(n+1);
printf("%.6lf",ans);

[NOIP2016 提高组]换教室

首先认真读题,注意各个变量的含义

先用 \(\tt{Floyd}\) 跑出多源最短路,存储在 \(s_{i,j}\) 中。

设计DP,令 \(dp_{i,j,k}\) 表示递推到第 \(i\) 节课程,申请了 \(j\) 节课,以及本节课是否申请了 \((k\in [0,1])\) 的期望路程。哎我真是唐,开始觉得是申请成功j节,觉得m是申请成功的上界。申请是一回事,人家同意是另一回事...

接下来,就是 恶心的 转移方程:

\[dp_{i,j,0}=\min \begin{cases} dp_{i-1,j,0}+s_{c_{i-1},c_i} \\ dp_{i-1,j,1}+p_{i-1}\times s_{d_{i-1},c_i}+(1-p_{i-1})\times s_{c_{i-1},c_i} \end{cases} \]

为什么呢,由于这次不申请,那么此次必定在 \(c_i\) 上课,但是上一次可以申请也可以不申请,不申请则一定是从 \(c_{i-1}\) 出发,若申请则有 \(p_{i-1}\) 的概率从 \(d_{i-1}\) 出发,以及 \(1-p_{i-1}\) 的概率从 \(c_{i-1}\) 出发即可。

\(dp_{i,j,1}\) 同理,不再赘述,大力分讨。

\[dp_{i,j,1}=\min \begin{cases} dp_{i-1,j-1,0}+p_i\times s_{c_{i-1},d_i}+(1-p_i)\times s_{c_{i-1},c_i} \\ dp_{i-1,j-1,1}+p_{i-1}\times p_i\times s_{d_{i-1},d_i}+p_{i-1}\times (1-p_i)\times s_{d_{i-1},c_i}+(1-p_{i-1})\times p_i\times s_{c_{i-1},d_i}+(1-p_{i-1})\times (1-p_i)\times s_{c_{i-1},c_i} \end{cases} \]

CODE
#include<bits/stdc++.h>
using namespace std;
#define read read()
#define pt puts("")
inline int read{int x=0,f=1;char c=getchar();while(c<'0'||c>'9') {if(c=='-')  f=-1;c=getchar();}while(c>='0'&&c<='9')   x=(x<<3)+(x<<1)+c-'0',c=getchar();return f*x;
}
#define T 2010
#define N 310
const int inf = 1e8;
int t,m,n,e;
int c[T],d[T];
double p[T];
int s[N][N];
void Floyed(){for(int k=1;k<=n;k++)for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(s[i][k]+s[k][j]<s[i][j])s[i][j]=s[i][k]+s[k][j];
}
double dp[T][T][2];
signed main()
{t=read,m=read,n=read,e=read;for(int i=1;i<=t;i++)  c[i]=read;for(int i=1;i<=t;i++)  d[i]=read;for(int i=1;i<=t;i++)  scanf("%lf",&p[i]);for(int i=1;i<=n;i++)  for(int j=1;j<=n;j++)  s[i][j]=(i==j?0:inf);for(int i=1,a,b,w;i<=e;i++){a=read,b=read,w=read;s[a][b]=s[b][a]=min(s[a][b],w);}Floyed();for(int i=1;i<=t;i++)for(int j=0;j<=t;j++)dp[i][j][0]=dp[i][j][1]=1e8;dp[1][0][0]=dp[1][1][1]=0;for(int i=2;i<=t;i++){for(int j=0;j<=min(i,m);j++){if(!j)dp[i][0][0]=dp[i-1][0][0]+s[c[i-1]][c[i]];else{dp[i][j][0]=min(dp[i-1][j][0]+s[c[i-1]][c[i]],dp[i-1][j][1]+(1-p[i-1])*s[c[i-1]][c[i]]+p[i-1]*s[d[i-1]][c[i]]);dp[i][j][1]=min(dp[i-1][j-1][0]+p[i]*s[c[i-1]][d[i]]+(1-p[i])*s[c[i-1]][c[i]],dp[i-1][j-1][1]+p[i-1]*p[i]*s[d[i-1]][d[i]]+p[i-1]*(1-p[i])*s[d[i-1]][c[i]]+(1-p[i-1])*p[i]*s[c[i-1]][d[i]]+(1-p[i-1])*(1-p[i])*s[c[i-1]][c[i]]);}}}double ans=1e9;for(int i=0;i<=m;i++)ans=min(ans,min(dp[t][i][0],dp[t][i][1]));printf("%.2lf",ans);return 0;
}

[SCOI2008]奖励关

由于正推灰常不好推,我们考虑倒推。

发现 \(n\leq 15\),那么状压。

\(dp_{i,t}\) 表示从第 \(1\) 轮到第 \(i-1\)取过的宝物状压为 \(t\),下面从第 \(i\) 轮到第 \(k\)的最大期望分值。

那么当符合吃宝物 \(j\) 条件时,\(dp[i][t]=\max(dp_{i+1,t},dp_{i+1,t|2^j}+p_j)\)

最后 \(dp_{1,0}\) 即为所求。

我们发现,大多数概率期望DP都可以通过从唯一的末状态倒推回不确定的初状态。

CODE
#include<bits/stdc++.h>
using namespace std;
#define read read()
#define pt puts("")
inline int read{int x=0,f=1;char c=getchar();while(c<'0'||c>'9') {if(c=='-')  f=-1;c=getchar();}while(c>='0'&&c<='9')   x=(x<<3)+(x<<1)+c-'0',c=getchar();return f*x;
}
int k,n;
int p[16];
int s[16];
#define MAX ((1<<n)-1)
double dp[110][1<<16];
signed main()
{k=read,n=read;for(int x,i=1;i<=n;i++){p[i]=read;x=read; while(x) s[i]|=1<<(x-1),x=read;}for(int i=k;i>=1;--i){for(int t=0;t<=MAX;t++){for(int j=1;j<=n;j++){if((t|s[j])==t)  dp[i][t]+=max(dp[i+1][t],dp[i+1][t|(1<<(j-1))]+p[j]);else  dp[i][t]+=dp[i+1][t];}dp[i][t]=dp[i][t]/n;}}printf("%.6lf",dp[1][0]);return 0;
}

[NOI2005]聪聪与可可

一眼最短路,\(\tt{SPFA}\)(Wang54321称这是 \(\tt{BFS}\),称 \(\tt{SPFA}\) 碰瓷) 或者 \(\tt{Dijkstra}\) 堆优化,处理出多源最短路 \(s_{i,j}\),并处理出 \(nxt_{i,j}\) 表示猫在 \(i\),鼠在 \(j\) 时,猫靠近鼠的下一步应去往的位置。

进行 DP,还是一样,倒推 DP,设 \(dp_{i,j}\),表示猫在 \(i\),鼠在 \(j\),猫抓到鼠的期望时间。

考虑进行转移:

  • 若此时猫鼠在一块,说明已经抓到。
  • 若此时猫鼠距离小于等于2,则一步就可抓到。
  • 否则,猫一定要向鼠走两步,即移动到 \(nxt_{nxt_{i,j},j}\),然后继续搜索,鼠会以 \(\frac{1}{k_j+1}\) 的概率走到相邻节点或是不走,直接求和即可,记得此时初始值为 \(1\),并记得加上留在原位的情况。
CODE
#include<bits/stdc++.h>
using namespace std;
#define read read()
#define pt puts("")
inline int read{int x=0,f=1;char c=getchar();while(c<'0'||c>'9') {if(c=='-')  f=-1;c=getchar();}while(c>='0'&&c<='9')   x=(x<<3)+(x<<1)+c-'0',c=getchar();return f*x;
}
const int N = 1010;
const int inf = 1e8;
int n,m;
int cat,rat;
struct EDGE{int next,to;
}e[N<<1];
int head[N],tot;
void add(int u,int v){e[++tot]={head[u],v};head[u]=tot;
}
double dp[N][N];
int k[N];
int dis[N][N],nxt[N][N];
queue<int>q;
bool vis[N];
void SPFA(){for(int i=0;i<=n;i++)for(int j=0;j<=n;j++)dis[i][j]=nxt[i][j]=inf;for(int i=1;i<=n;i++){q.push(i);dis[i][i]=0;vis[i]=1;while(!q.empty()){int x=q.front();q.pop();vis[x]=0;int y;for(int j=head[x];j;j=e[j].next){y=e[j].to;if(dis[i][x]+1<dis[i][y]){dis[i][y]=dis[i][x]+1;if(!vis[y])  vis[y]=1,q.push(y);}}}}
}
void init(){for(int x=1,y;x<=n;x++){for(int i=head[x];i;i=e[i].next){int j=e[i].to;for(int y=1;y<=n;y++){if(dis[j][y]+1==dis[x][y]){nxt[x][y]=min(nxt[x][y],j);}}}}
}double DP(int u,int v){if(dp[u][v])  return dp[u][v];if(!dis[u][v])  return 0;if(dis[u][v]<=2)  return 1;dp[u][v]=1;int t=nxt[nxt[u][v]][v];for(int i=head[v];i;i=e[i].next){int p=e[i].to;dp[u][v]+=DP(t,p)/(k[v]+1);}dp[u][v]+=DP(t,v)/(k[v]+1);return dp[u][v];
}signed main()
{n=read,m=read;cat=read,rat=read;for(int a,b,i=1;i<=m;i++){a=read,b=read;add(a,b),add(b,a);k[a]++;k[b]++;}SPFA();init();double ans=DP(cat,rat);printf("%.3lf",ans);return 0;
}

[SHOI2014]概率充电器

大难题,贺了

首先,对于两件事情 \(A,B\),发生概率分别为 \(P(A),P(B)\),那么至少发生 \(A,B\) 其中一种的概率为:

\[P(AB)=P(A)+P(B)-P(A)*P(B) \]

由于每个概率对期望的贡献都乘1,因此答案就是每个节点来电概率之和。

那么我们考虑分讨,某节点的来电情况:

  1. 自己来电
  2. 儿子给电
  3. 父亲给电

规定 \(dp_i\) 表示节点 \(i\) 来电的概率,\(p_i\) 表示节点 \(i\) 自己来电的的概率,\(p(i,j)\) 表示 \(i,j\) 之间导线导电的概率。

考虑树形 DP,进行两次 \(\tt{DFS}\),第一次将儿子的信息传到父亲,即 \(up\);第二次将父亲信息传到儿子,即 \(down\)

  • \(up\)

    • 处理第一种情况,令 \(dp_i\) 的初始值为 \(p_i\) 即可。
    • 处理第二种情况,考虑从儿子回溯时,加上儿子的贡献,即 \(dp_x=dp_x+dp_y\times p_{x,y}\),当然,此处的 \(+\) 应该是上文提到的 \(P(AB)=P(A)+P(B)-P(A)*P(B)\)
  • \(down\)

    • 处理第三种情况,首先求出父节点来电的概率 \(p_a\),我们发现由 \(up\) 可以得 \(p_a+p_b-p_a\times p_b=dp_x\),此时 \(p_b\) 仍为 \(dp_y\times p_{x,y}\),但是由于我们从上往下跑,此时 \(dp_x\) 已经包含了第三种情况,因此我们可以直接处理 \(p_a=\dfrac{dp_x-p_b}{1-p_b}\),然后 \(dp_y\) 就可以加上 \(p_a\times p_{x,y}\) 了,当然也是上文的方式。
  • 最后 \(\sum \limits _{i=1}^{n} dp_i\)

CODE
#include<bits/stdc++.h>
using namespace std;
#define read read()
#define pt puts("")
inline int read{int x=0,f=1;char c=getchar();while(c<'0'||c>'9') {if(c=='-')  f=-1;c=getchar();}while(c>='0'&&c<='9')   x=(x<<3)+(x<<1)+c-'0',c=getchar();return f*x;
}
const int N = 5e5+10;
int n;
struct EDGE{int next,to;double p;}e[N<<1];int head[N],tot;
void add(int u,int v,double p){e[++tot]={head[u],v,p};head[u]=tot;}
int p[N];
double dp[N];double Plus(double pa,double pb){return pa+pb-pa*pb;
}void dfs_up(int x,int fa){for(int i=head[x];i;i=e[i].next){int y=e[i].to;if(y==fa)  continue;dfs_up(y,x);dp[x]=Plus(dp[x],dp[y]*e[i].p);}
}void dfs_down(int x,int fa){for(int i=head[x];i;i=e[i].next){int y=e[i].to;if(y==fa)  continue;double pb=dp[y]*e[i].p;if(pb==1.0){dfs_down(y,x);continue;}double pa=(dp[x]-pb)/(1-pb);dp[y]=Plus(dp[y],pa*e[i].p);dfs_down(y,x);}
}
double ans;
signed main()
{n=read;for(int a,b,c,i=1;i<n;i++){a=read,b=read,c=read;add(a,b,c*0.01),add(b,a,c*0.01);}for(int i=1;i<=n;i++)  p[i]=read,dp[i]=p[i]*1.0/100.0;dfs_up(1,0);dfs_down(1,0);for(int i=1;i<=n;i++){ans+=dp[i];}printf("%.6lf",ans);return 0;
}

数位DP

数位DP,大体打法有两种,即递推和记搜,我比较Cai,只会记搜

花神的数论题

要求 \(\prod \limits _{i=1}^{N} sum(i)\),考虑枚举 \(sum(i)\),即枚举数中1的个数 \(k\),求出满足 \(sum(i)=k\)\(i\) 的个数,然后快速幂求解即可。

这是板,考虑设计 \(dp_{i,j,k}\) 表示处理到第 \(i\) 位,当前已经有了 \(j\)\(1\),我们的目标是 \(k\)\(1\) 时的数的个数,然后进行记搜,为了确保比 \(n\) 小,我们再规定一个 \(limit\) 即可。

CODE
#include<bits/stdc++.h>
using namespace std;
#define mod 10000007
#define int long long
#define read read()
#define pt puts("")
inline int read{int x=0,f=1;char c=getchar();while(c<'0'||c>'9') {if(c=='-')  f=-1;c=getchar();}while(c>='0'&&c<='9')   x=(x<<3)+(x<<1)+c-'0',c=getchar();return f*x;
}
void write(int x){if(x<0)  putchar('-'),x=-x;if(x>9)  write(x/10);putchar(x%10+'0');return;
}
#define N 55
int n;
int len,a[55];
int ans=1ll;
int qpow(int x,int y){int res=1;while(y){if(y&1)  res=res*x%mod;x=x*x%mod;y>>=1;}return res;
}int dp[N][N][N][2],sum[N];
int DP(int p,int t,int s,bool limit){if(t > s) return 0;if(p>len)  return t==s;if(dp[p][t][s][limit]!=-1)  return dp[p][t][s][limit];//if(!limit && dp[p][t][s]!=-1)  return dp[p][t][s];  这是等价的,但是要注意下面给它赋值时要在 !limit 时才能赋值。int up=limit?a[p]:1;int res=0;for(int i=0;i<=up;i++){res+=DP(p+1,t+(i==1),s,i==up&&limit);}dp[p][t][s][limit]=res;return res;
}
signed main(){n=read;for(len=0;n;n>>=1)  a[++len]=n&1;reverse(a+1,a+len+1);memset(dp,-1,sizeof(dp));for(int i=1;i<=50;i++){sum[i]+=DP(1,0,i,1);}for(int i=1;i<=50;i++){ans=ans*qpow(i,sum[i])%mod;}write(ans);return 0;
}

类似的题还有 [0和1的熟练],题意是区间 \([l,r]\) 中有多少数字的二进制表示(不含前导零)中0的个数不少于1的个数的数的个数。一样的思路,可以枚举1的个数,然后注意判前导0的个数就好了。

CODE
#include<bits/stdc++.h>
using namespace std;
#define read read()
#define pt puts("")
inline int read{int x=0,f=1;char c=getchar();while(c<'0'||c>'9') {if(c=='-')  f=-1;c=getchar();}while(c>='0'&&c<='9')   x=(x<<3)+(x<<1)+c-'0',c=getchar();return f*x;
}
void write(int x){if(x<0)  putchar('-'),x=-x;if(x>9)  write(x/10);putchar(x%10+'0');return;
}
#define N 35
int l,r;
int a[N],n;
int dp[N][N][N];
int DP(int p,int t,bool limit,int lead){if(!p)  return (n-t-lead>=t)?1:0;if(!limit && dp[p][t][lead]!=-1)  return dp[p][t][lead];int up=limit?a[p]:1;int res=0;for(int i=0;i<=up;i++)res+=DP(p-1,t+(i==1),limit&&(i==up),(lead==n-p)?lead+(i==0):lead);if(!limit) dp[p][t][lead]=res;return res;
}
int solve(int x){int res=0;memset(dp,-1,sizeof(dp));for(n=0;x;x>>=1) a[++n]=x&1;res+=DP(n,0,1,0);return res;
}
signed main(){l=read,r=read;write(solve(r)-solve(l-1));return 0;
}

haha数

我们发现,若设原数为 \(x\),每一位为 \(a_i\),使 \(\forall a_i | x\),等价于使 \(\mathrm{lcm}_{i=1}^n\ {a_i} | x\)
因此,我们要记录各位上数的最小公倍数。那么原数怎么记录,我们知道 \(1\) ~ \(9\) 的最小公倍数为 \(2520\),那么一定有 \(\mathrm{lcm}_{i=1}^n\ {a_i} | 2520\),所以我们只要记录原数关于 \(2520\) 的余数即 \(x\% 2520\) 的值。

所以我们设 \(dp_{i,x,lcm}\),考虑记录当前位,原数除于 \(2520\) 的余数,和各位的最小公倍数。要开 \(20\times 2520\times 2520\),会爆,又发现各位可能的最小公倍数只有 \(48\) 种,我们可以把最后一维压成 \(50\),建立一一映射关系,然后直接记搜即可。

对于记搜有一个注意点,一定要从第 \(n\) 位往第 \(1\) 位倒序跑,我一开始甚至把 \(a\) 数组翻转,然后从 \(1\)\(n\) 跑,这两种看似等价,实则不一样——考虑倒着跑是还剩 \(i\) 位,下一次可以直接继承以记搜,但是正跑就会 \(\text{WA}\),必须每次清空,就会 \(\text{T}\)。所以我们必须倒着跑,这也是最正确的记搜形式。

CODE
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define read read()
#define pt puts("")
inline ll read{ll x=0,f=1;char c=getchar();while(c<'0'||c>'9') {if(c=='-')  f=-1;c=getchar();}while(c>='0'&&c<='9')   x=(x<<3)+(x<<1)+c-'0',c=getchar();return f*x;
}
void write(ll x){if(x<0)  putchar('-'),x=-x;if(x>9)  write(x/10);putchar(x%10+'0');return;
}
#define mod 2520
int Gcd(int a,int b){return b?Gcd(b,a%b):a;}
int Lcm(int a,int b){return b?a/Gcd(a,b)*b:a;}
int mapp[2525],total;
ll l,r;
int a[20],n;
ll dp[20][2525][50];
ll DP(int p,int r,int lcm,int limit){if(!p)  return (r%lcm==0)?1:0;if(!limit&&dp[p][r][mapp[lcm]])  return dp[p][r][mapp[lcm]];int up=limit?a[p]:9;ll res=0;for(int i=0;i<=up;i++){res+=DP(p-1,(r*10+i)%mod,Lcm(lcm,i),limit&(i==up));}if(!limit)  dp[p][r][mapp[lcm]]=res;return res; 
}
ll solve(ll x){for(n=0;x;x/=10)  a[++n]=x%10;return DP(n,0,1,1);
}
signed main()
{#ifndef ONLINE_JUDGEfreopen("lty.in","r",stdin);freopen("lty.out","w",stdout);#endiffor(int i=1;i<=2520;i++)  if(mod%i==0)  mapp[i]=++total;for(int T=read;T;--T){l=read,r=read;ll ans=solve(r)-solve(l-1);write(ans);pt;}return 0;
}

[ZJOI2010] 数字计数

递推一波,考虑预处理出 \(dp_{i,j,k}\) 为具有 \(i\) 位,最高位(即第 \(i\) 位)为 \(j\),数 \(k\) 出现的次数。转移方程很好想,

\[dp_{i,j,k}=(\sum _{p=0}^9 dp_{i-1,p,k})+[j=k]\times 10^{i-1} \]

然后思索填数:

  • 考虑有前导 \(0\) 的数,这些数一定小于 \(x\),直接不用考虑上界,枚举前导 \(0\) 的个数:\(\sum \limits _{i=1}^{n-1} \sum \limits _{j=1}^9 dp_{i,j,k}\)
  • 考虑无前导 \(0\)
    • 最高位不卡上界,后面还是随便填:\(\sum \limits _{i=1}^{s_n-1} dp_{n,i,k}\)
    • 最高位卡上界,后面也要注意上界:\(\sum \limits _{i=1}^{n-1} \sum \limits _{j=1}^{s_i-1} dp_{i,j,k}\)
  • 我们发现这样还是有漏情况——当你处理第 \(i\) 位时,你只加上了后面的第 \(i-1\) 位的贡献,而它本身还有后面 \(i-1\) 位数的大小的贡献没有算,最后枚举每一位处理即可。
CODE
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define read read()
#define pt puts("")
inline int read{int x=0,f=1;char c=getchar();while(c<'0'||c>'9') {if(c=='-')  f=-1;c=getchar();}while(c>='0'&&c<='9')   x=(x<<3)+(x<<1)+c-'0',c=getchar();return f*x;
}
void write(int x){if(x<0)  putchar('-'),x=-x;if(x>9)  write(x/10);putchar(x%10+'0');return;
}
int a,b;
int dp[15][15][15];
int p10[15];
int ans1[11],ans2[11];
int s[15],n;
void solve(int x,int ans[]){int X=x;for(n=0;x;x/=10)  s[++n]=x%10;for(int k=0;k<=9;k++){for(int i=n-1;i>=1;i--)for(int j=1;j<=9;j++)ans[k]+=dp[i][j][k];for(int j=1;j<s[n];j++)  ans[k]+=dp[n][j][k];int num=0;for(int i=n-1;i>=1;--i)for(int j=0;j<s[i];j++)ans[k]+=dp[i][j][k];}for(int i=n;i>=1;--i)ans[s[i]]+=X%p10[i-1]+1;
}signed main(){a=read,b=read;p10[0]=1;for(int i=1;i<=12;i++)  p10[i]=p10[i-1]*10;for(int i=0;i<=9;i++)  dp[1][i][i]=1;for(int i=2;i<=12;i++){for(int j=0;j<=9;j++){for(int k=0;k<=9;k++){for(int p=0;p<=9;p++)dp[i][j][k]+=dp[i-1][p][k];if(j==k)  dp[i][j][k]+=p10[i-1];}}}solve(a-1,ans1);solve(b,ans2);for(int i=0;i<=9;i++)write(ans2[i]-ans1[i]);putchar(' ');return 0;
}

计数DP

有空再补

闲话

\([2024.7.4]\) 中考出分了,以 \(663\) 分喜提全市 \(\tt{Rank} 2\),仅落后于 \(\tt{Rank} 1\) \(0.5\) 分。可是人们只会记得第一……

\([2024.7.4]\) 一下午加一晚上,虽然下午有个小体活,但是只打了8个题的博客还是太低效了……

\([2024.7.5]\) 学校OJ上的"一言"

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/738583.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Power BI实用技巧——外部工具DAX studio

Power BI实用技巧——外部工具DAX studio 当你想要将Power BI表格对象数据导出,Power BI却告诉你:您的数据过大可能会执行一些数据抽样,点击继续导出一份CSV文件,却发现Power BI只能导出三万行数据,这该怎么办呢? 这里我们就要推荐一款非常实用的外挂级软件——DAX studi…

一款EF Core下高性能、轻量级针对分表分库读写分离的解决方案

前言 今天大姚给大家分享一款EF Core下高性能、轻量级针对分表分库读写分离的解决方案,开源(Apache License)的EF Core拓展程序包:ShardingCore。 ShardingCore项目介绍 ShardingCore是一款开源、简单易用、高性能、普适性,针对EF Core生态下的分表分库的扩展解决方案,支…

java中堆污染(heap pollution)以及@SafeVarargs注解使用

什么是堆污染 heap pollution堆污染发生在使用可变参数(varargs)或泛型时,将不兼容的类型插入到一个泛型对象中。这会导致在运行时尝试访问这些对象时发生 ClassCastException。例如:public static void heapPollutionExample(List<String>... stringLists) {Object[…

e语音 【删除文本右边字符】

删除 “#换行符”代码本文来自博客园,作者:__username,转载请注明原文链接:https://www.cnblogs.com/code3/p/18284992

从OpenAI停服看中国市场:国产替代崛起的机遇与挑战

一、OpenAI 停服事件背景 OpenAI 自 2020 年推出 GPT-3 以来,在全球范围内引起了极大的反响。其强大的自然语言处理能力使其成为许多企业和开发者的首选工具。然而,2024 年 6 月 25 日,许多中国用户收到了一封来自 OpenAI 的邮件,邮件中明确表示,自 2024 年 7 月 9 日起,…

云锵投资 2024 年 6 月简报

季报摘要行情:二次探底; 微盘策略:大幅回撤,逻辑基础小幅动摇,但继续运行; 本季度量化基金策略业绩:-4.3085%,中,全国排名:7532;平均 Beta:1.00; 本季度量化股票策略业绩:-16.8934%,差,全国排名:11198;平均 Beta:1.84;(优良中差,表明全国排名四位分) 行…

全网最适合入门的面向对象编程教程:09 类和对象的Python实现-类之间的关系,你知道多少?

本文主要对类之间的关系进行了基本介绍,包括继承、组合、依赖关系,并辅以现实中的例子加以讲解,同时说明了不同关系的特点和应用场景。全网最适合入门的面向对象编程教程:09 类和对象的 Python 实现-类之间的关系,你知道多少? 摘要: 本文主要对类之间的关系进行了基本介…

[LeetCode] 274. H-Index

意外的简单。 class Solution:def hIndex(self, citations: List[int]) -> int:sorted_list = sorted(citations, reverse=True)ret = 0for i,element in enumerate(sorted_list[:1000]):curr = min(i+1, element)if curr > ret:ret = currreturn ret

数据换机

图1为本系统的方法的流程示意图图2为首次拷贝到X中断需要遍历的文件示意图图3为非首次拷贝找到X中断点需要遍历的文件示意图 实现的功能支持换机对SD卡的数据迁移大文件按阈值切成切片文件小文件和切片文件按阈值分段拷贝切片文件的恢复小文件和切片文件从换机cache下恢复到三…

实战篇——文件上传漏洞upload-labs-master靶场实战一

实战篇——文件上传漏洞upload-labs-master靶场实战(1) 前端验证绕过 (1) 篡改js代码 直接上传一句话木马失败:查看页面源代码:可见前端通过checkFile函数对上传文件的后缀名进行了验证。 使用Tampermonkey自定义js脚本,用于删除form表单的onsubmit属性:启用脚本,刷新页面…

国产数据库人大金仓Kingbase数据迁移工具

转载:国产数据库人大金仓Kingbase数据迁移工具-CSDN博客 注意:Kingbase自带的迁移工具,只能从其它数据库迁移到Kingbase数据库 适配数据库安装的时候建议使用完全安装(数据库可以不启动),后续也可以全部默认(如安装数据库,相关 参数设置可参考人大金仓(Kingbase)部署…

selenium操作

selenium介绍开发使用有头浏览器,部署使用无界面浏览器 selenium工作原理利用浏览器原生的API,封装成一套更加面向对象的Selenium WebDriver API,直接操作浏览器页面里的元素,甚至操作浏览器本身(截屏,窗口大小,启动,关闭,安装插件,配置证书之类的) selenium模块与d…

《Deep Learning》(深度学习)中英文双版PDF免费下载

“深度学习”经典著作《Deep Learning》中文版pdf免费下载。 《Deep Learning》(深度学习)是一本皆在帮助学生和从业人员进入机器学习领域的教科书,以开源的形式免费在网络上提供,这本书是由学界领军人物 Ian Goodfellow、Yoshua Bengio 和 Aaron Courville 合力打造。中文…

微服务异常问题

多服务间,被依赖服务代码更新,依赖服务不生效问题被依赖服务代码更新后,jar包会更新 依赖服务并不是通过http直接调用依赖服务的代码,而是通过依赖jar包的方式,把被依赖服务更新后的jar包更新到依赖服务中即可。 举例: 有A服务,B服务;其中A服务依赖B服务。 当A服务有代…

深度学习--强化学习--基本概念Q V--94

目录1. 强化学习2. 马尔科夫链3. Q值和V值 1. 强化学习 首先我们需要明确,强化学习的任务是什么? 这用大白话说:就是我们希望用强化学习的方式,使智能体获得独立自主地完成某种任务的能力。 智能体学习和工作的地方,我们就称为环境。 注意!所谓独立自主,就是智能体一旦启…

京东毫秒级热key探测框架设计与实践,已实战于618大促

在拥有大量并发用户的系统中,热key一直以来都是一个不可避免的问题。或许是突然某些商品成了爆款,或许是海量用户突然涌入某个店铺,或许是秒杀时瞬间大量开启的爬虫用户, 这些突发的无法预先感知的热key都是系统潜在的巨大风险。 风险是什么呢?主要是数据层,其次是服务层…

刷题Phuck2--data协议差异

刷题Phuck2 使用arjun扫出hl参数,获取到源码 ​​ 源码: <?phpstream_wrapper_unregister(php);if(isset($_GET[hl])) highlight_file(__FILE__);$mkdir = function($dir) {system(mkdir -- .escapeshellarg($dir));};$randFolder = bin2hex(random_bytes(16));$mkdir(us…

常见Linux命令

1、查看目录:ls 常用用法: ls -l :以列表的形式展示;简写ll效果展示:2、终端清屏:clear 常用用法: ctr+L:清空屏幕当前的内容,不会重置终端效果展示: 使用前使用后3、切换目录:cd 常用用法:cd /:切换到根目录cd /xx(目录名) :切换到根目录下的xx目录cd ..:切换…

R语言大学城咖啡店消费问卷调查报告:信度分析、主成分分析可视化

全文链接:https://tecdat.cn/?p=34656 原文出处:拓端数据部落公众号 本次调查旨在了解文汇路咖啡店的市场状况,以便为学校周边咖啡店的经营发展提供积极的引导意义。我们通过问卷调查的方式,收集了大量的数据,通过r软件对数据进行了基本情况分析、信度分析、问卷调查数据…

R语言武汉流动人口趋势预测:灰色模型GM(1,1)、ARIMA时间序列、logistic逻辑回归模型|附代码数据

全文链接:http://tecdat.cn/?p=32496 原文出处:拓端数据部落公众号 人口流动与迁移,作为人类产生以来就存在的一种社会现象,伴随着人类文明的不断进步从未间断。 人力资源是社会文明进步、人民富裕幸福、国家繁荣昌盛的核心推动力量。当前,我国经济正处于从以政府主导的投…