UESTC 884 方老师的专题讲座

数位DP问题。

定义:cnt[L][K]表示长度为L,最高位为K的满足条件C的个数。

首先预处理出cnt数组,枚举当前长度最高位和小一个长度的最高位,如果相差大于2则前一个加上后一个的方法数。

然后给定n,计算[1,n-1]中满足条件C的数的个数。

设有K位数,则不足K位的累加,然后枚举K位数的情况,从高位到低位枚举,每次枚举到比该位小1的数,注意:如果某时刻该数中有两位相差大于2,则再枚举下去已经没有意义,因为以后的数再也不会满足条件C,这时退出即可。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#define Mod 1000000007
#define ll long long
using namespace std;
#define N 100007

ll cnt[22][12]; //cnt[L][K]:长度为L,最高位为K的满足条件C的数的个数
ll NUM[21];

ll DP(ll a) //[1,n-1]
{
int i,j,K;
int pre,head;
ll res = 0;
K = 0;
while(K <= 18 && NUM[K] <= a)
K++;
K--;
//cout<<"K is "<<K<<endl;
for(i=1;i<K;i++) //所有小于a长度的长度
for(j=1;j<=9;j++) //所有首位
res += cnt[i][j];
head = a/NUM[K]; //数a的首位
for(i=1;i<head;i++) //从1开始(不含前导0)
res += cnt[K][i];
a %= NUM[K]; //去除首位
pre = head; //多一位的首位
for(i=K-1;i>=1;i--) //长度逐次递减,高位到低位
{
head = a/NUM[i];
for(j=0;j<head;j++) //小于a的当前位的数做首位
if(abs(pre-j) >= 2)
res += cnt[i][j];
if(abs(head-pre) < 2) //如果前面某两位出现差小于2,再枚举后面的数就没意义了,因为无论如何都不会满足了。
break;
pre = head;
a %= NUM[i]; //一个一个去除
}
return res;
}

int main()
{
int i,j,l,k;
ll a,b;
j = 0;
NUM[j++] = 0LL;
for(i=1;i<=19;i++)
NUM[j++] = (ll)pow(10,i-1);
//for(i=0;i<j;i++)
//cout<<NUM[i]<<" ";
//cout<<endl;
memset(cnt,0,sizeof(cnt));
for(k=0;k<=9;k++)
cnt[1][k] = 1;
for(l=2;l<=18;l++)
{
for(i=0;i<=9;i++) //长度为l时的首位
{
for(k=0;k<=9;k++) //长度为l-1时的首位
{
if(abs(k-i) >= 2)
cnt[l][i] += cnt[l-1][k];
}
}
}
for(k=0;k<=9;k++) //10^18
if(abs(1-k) >= 2)
cnt[19][1] += cnt[18][k];

while(scanf("%lld%lld",&a,&b)!=EOF)
{
printf("%lld\n",DP(b+1)-DP(a));
}
return 0;
}

UESTC 884 方老师的专题讲座

时间: 2024-10-13 09:47:11

UESTC 884 方老师的专题讲座的相关文章

UESTC 899 方老师和农场 --双连通分量的构造

首先将原图中的连通分量缩点,一定可以将原图缩成一棵树的形式,然后统计这棵树的叶子节点个数,答案就是(leaf+1)/2.这里不再证明,可以画个图看一下. (简单说明一下,首先把两个最近公共祖先最远的两个叶节点之间连接一条边,这样可以把这两个点到祖先的路径上所有点收缩到一起,因为一个形成的环一定是双连通的.然后再找两个最近公共祖先最远的两个叶节点,这样一对一对找完,恰好是(leaf+1)/2次,把所有点收缩到了一起.  --Byvoid) 怎么统计呢?用并查集缩点,可以知道,缩点后留下的边全部是原

UESTC 916 方老师的分身III --拓扑排序

做法: 如果有a<b的关系,则连一条a->b的有向边,连好所有边后,找入度为0的点作为起点,将其赋为最小的价值888,然后其所有能到的端点,价值加1,加入队列,删去上一个点,然后循环往复,直到队列为空,即每个点都赋予了一个权值为止. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #in

UESTC 901 方老师抢银行 --Tarjan求强连通分量

思路:如果出现了一个强连通分量,那么走到这个点时一定会在强连通分量里的点全部走一遍,这样才能更大.所以我们首先用Tarjan跑一遍求出所有强连通分量,然后将强连通分量缩成点(用到栈)然后就变成了一个DAG(有向无环图),然后跑一遍DFS,不断加上遍历点的权值,如果到了网吧,则更新一遍答案,因为可以出去了. 求强连通分量时,如果low[u] == dfn[u],说明形成了一个新的强连通分量,且根为u.具体求强连通分量见:http://www.cnblogs.com/whatbeg/p/377642

UESTC 914 方老师的分身I Dijkstra

题意:求有向图的往返最短路的最长长度. 分析:求第一次到所有点的距离可以用一次Dijkstra求最短路求出来.考虑回来的路,想想就知道,从每个点回来的路即为将边的方向反转再求一次最短路后的结果. 所以此题为求两次最短路. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #define Mod 100

UESTC 900 方老师炸弹 --Tarjan求割点及删点后连通分量数

Tarjan算法. 1.若u为根,且度大于1,则为割点 2.若u不为根,如果low[v]>=dfn[u],则u为割点(出现重边时可能导致等号,要判重边) 3.若low[v]>dfn[u],则边(u,v)为桥(封死在子树内),不操作. 求割点时,枚举所有与当前点u相连的点v: 1.是重边: 忽略 2.是树边: Tarjan(v),更新low[u]=min(low[u],low[v]); 子树个数cnt+1.如果low[v] >= dfn[u],说明是割点,割点数+1 3.是回边: 更新lo

UESTC 917 方老师的分身IV --求欧拉路径

判断欧拉路径是否存在及求出字典序最小的欧拉路径问题(如果存在). 将字符串的第一个字母和最后一个字母间连边,将字母看成点,最多可能有26个点(a-z),如果有欧拉路径,还要判断是否有欧拉回路,如果有,则需要找一个字典序最小的点开始生成这条链,否则以起点开始生成链,起点即为出度比入度大1的点. 欧拉路径是否存在的判定: 1.全部点在一个联通块                               ----用并查集判联通块的数量2.所有点出度入度相等                      

UESTC 915 方老师的分身II --最短路变形

即求从起点到终点至少走K条路的最短路径. 用两个变量来维护一个点的dis,u和e,u为当前点的编号,e为已经走过多少条边,w[u][e]表示到当前点,走过e条边的最短路径长度,因为是至少K条边,所以大于K条边的当做K条边来处理就好了.求最短路的三个算法都可以做,我这里用的是SPFA,比较简洁. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #incl

UESTC 898 方老师和缘分 --二分图匹配+强连通分量

这题原来以为是某种匹配问题,后来好像说是强连通的问题. 做法:建图,每个方老师和它想要的缘分之间连一条有向边,然后,在给出的初始匹配中反向建边,即如果第i个方老师现在找到的是缘分u,则建边u->i.这样求出所有的强连通分量,每个强连通分量中方老师和缘分的数目一定是相等的,所以每个方老师一定可以找到与他在同一个强连通分量里的缘分,因为强连通分量中每个点都是可达的,某个方老师找到了其强连通分量中的非原配点,则该原配缘分一定可以在强连通分量中找到"新欢".可以画个图看看. 由于要构造非

UESTC 883 方老师与两个串

CF原题 由题可知,n,m太大,无法开出dp[n][m]的数组. 观察发现s/e最大为300,也就是说,选用第一种操作的次数不会超过300. 于是定义dp[i][j],第一个串的前i个数,使用了j次第一种操作的时候,第二个串最少删了多少个数. 转移有两种情况: 1.当前位置不删,这时dp[i][j]=dp[i-1][j]: 2.当前位置删,此时就需要在B串中找和当前位置的数相同的数的位置,并且只有在找到的位置大于dp[i-1][j-1]的时候才是可行的.为了保证dp[i][j]最小,显然就是找大