Bomb
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)Total Submission(s): 10496 Accepted Submission(s): 3695
Now the counter-terrorist knows the number N. They want to know the final points of the power. Can you help them?
The input terminates by end of file marker.
3 1 50 500
0 1 15HintFrom 1 to 500, the numbers that include the sub-sequence "49" are "49","149","249","349","449","490","491","492","493","494","495","496","497","498","499",so the answer is 15.
刚开始接触DP,加一块做的题还没有10道,今天用了一天的时间把这两道题全都弄明白了,感觉特别开心,期间,看了看别人的代码,而且还问了实验室的大神好多问题,才搞懂,不得不说,刚开始接触新知识真不容易。
这两道题实际上是一个思想,所以把他们放一块了,另外,题里面给的解析都在代码后面,为的是像我这样的菜鸟看的时候可以更容易明白。两道题的解析都不是太全面应该,我是这样认为,需要结合两道题来学习,所以,有什么不懂的可以上下结合来看。
状态转移:
dp[i][0]代表长度为 i 并且不含有49的数字的个数; dp[i][1]代表长度为 i 并且不含有49,但是最高位是9的数字的个数; dp[i][2]代表长度为 i 并且含有49的数字的个数。 数组 a[i] 从低位到高位存储 n 的每一位数字。 则:dp[i][0] = dp[i-1][0] * a[i] - dp[i-1][1]; 表示长度为 i 的不含有49的数字的个数等于长度为 i - 1 的不含有49的数字的个数*当前的数字,因为这个位置可以填0~a[i] - 1, 然后再减去长度为 i - 1 的最高位是9的数字的个数,因为如果长度为 i - 1 的最高位是9的话,那么高一位就不能填4了,否则就组成了49。 dp[i][1] = dp[i-1][0]; 表示长度为 i 的并且不含有49同时最高位是9的数字的个数等于,长度为 i - 1 的不含有49的数字的个数,因为只要在它的高一位加上一个9就可以了。 dp[i][2] = dp[i-1][2] * a[i] + dp[i-1][1]; 表示长度为 i 的含有49的数字的个数等于,长度为 i - 1 的数字的个数*当前的数字,再加上长度为 i - 1 的并且不含有49同时最高位是9的数字的个数, 因为这个时候,只要在高一位加上一个4就可以了,这样在最高的两位就组成了一个49。
//AC(2^63-1有18位) #include<iostream> #include<stdio.h> #include<string.h> #include<math.h> #include<ctype.h> #include<stdlib.h> #include<string> #include<algorithm> #include<vector> #include<set> #include<map> #include<list> #include<queue> #include<stack> #include<iomanip> #include<numeric> #include <istream> //基本输入流 #include <ostream> //基本输出流 #include <sstream> //基于字符串的流 #include <utility> //STL 通用模板类 #include <complex.h> //复数处理 #include <fenv.h> //浮点环境 #include <inttypes.h> //整数格式转换 #include <stdbool.h> //布尔环境 #include <stdint.h> //整型环境 #include <tgmath.h> //通用类型数学宏 #define L(a,b,c) for(int a=b;a>=c;a--) #define M(a,b,c) for(int a=b;a<=c;a++) #define N(a,b) memset(a,b,sizeof(a)); const int MAX=100000000; const int MIN=-MAX; using namespace std; long long dp[20][3]; void Init() { N(dp,0); dp[0][0]=1; M(i,1,18) { dp[i][0]=dp[i-1][0]*10-dp[i-1][1]; dp[i][1]=dp[i-1][0]; dp[i][2]=dp[i-1][2]*10+dp[i-1][1]; } } long long solve(long long n) { long long ans=0,a[22]; int len=0; while(n) { a[++len]=n%10; n/=10; } a[len+1]=0; bool flag=0; L(i,len,1) //从高位到低位讨论 { ans+=dp[i-1][2]*a[i]; //低位中含有49,高位随便一个1,2,3....a[i]都可以,a[i]是代表有几个数字,比如a[i]=5,那么代表有五个数字,0,1,2,3,4,比5小。 if(flag)//(注意::dp[i][0]和dp[i][2]为所有的个数)//如果有49,就随便选了,比如 495的时候,有490 491 492 493 494 //为什么不写(d[i-1][0]+dp[i-1][2])*a[i]呢,前面已经出现过49 //那么低位任意选择都可以,dp[i-1][0]是那些低位不出现49的,dp[i-1][2]是那些低位出现49的,按理说应该 //加上啊,BUT!!!清注意循环里面的第一句ans+=dp[i-1][2]*a[i]; 前面已经加上了dp[i-1][2]低位有 //49的情况了
//举例如下:49123,确定flag为1的哪一步时,a[i+1]=4;a[i]=9,i--,此时,a[i+2]=4;a[i+1]=9;a[i]=1;4和9都为高位
ans+=dp[i-1][0]*a[i]; if(!flag&&a[i]>4) ans+=dp[i-1][1];//低位中最高位含9 if(a[i+1]==4&&a[i]==9) flag=1; } if(flag) //最后一位数字未讨论,所以要对它进行判断 ans++; return ans; } int main() { Init(); int T; long long n; cin>>T; while(T--) { scanf("%lld",&n); printf("%I64d\n",solve(n)); } return 0; }
不要62
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 25556 Accepted Submission(s): 8869
Problem Description杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer)。 杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众。 不吉利的数字为所有含有4或62的号码。例如: 62315 73418 88914 都属于不吉利号码。但是,61152虽然含有6和2,但不是62连号,所以不属于不吉利数字之列。 你的任务是,对于每次给出的一个牌照区间号,推断出交管局今次又要实际上给多少辆新的士车上牌照了。
Input输入的都是整数对n、m(0<n≤m<1000000),如果遇到都是0的整数对,则输入结束。
Output对于每个整数对,输出一个不含有不吉利数字的统计个数,该数值占一行位置。
Sample Input1 100 0 0
Sample Output80//AC#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<ctype.h>
#include<stdlib.h>
#include<string>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
#include<list>
#include<queue>
#include<stack>
#include<iomanip>
#include<numeric>
#include <istream> //基本输入流
#include <ostream> //基本输出流
#include <sstream> //基于字符串的流
#include <utility> //STL 通用模板类
#include <complex.h> //复数处理
#include <fenv.h> //浮点环境
#include <inttypes.h> //整数格式转换
#include <stdbool.h> //布尔环境
#include <stdint.h> //整型环境
#include <tgmath.h> //通用类型数学宏
#define L(a,b,c) for(int a=b;a>=c;a--)
#define M(a,b,c) for(int a=b;a<=c;a++)
#define N(a,b) memset(a,b,sizeof(a));
const int MAX=100000000;
const int MIN=-MAX;
using namespace std;
int dp[10][3];
//dp[i][j],i代表数字的位数,j代表状况
//dp[i][0],表示不存在不吉利数字
//dp[i][1],表示不存在不吉利数字,且最高位为2
//dp[i][2],表示存在不吉利数字
void Init()
{
N(dp,0);
dp[0][0]=1;//讨论的时候会用到
for(int i=1;i<=6;i++) //一共6位数
{
dp[i][0]=dp[i-1][0]*9-dp[i-1][1]; //数位不含有4,而且次高位不能含有2
dp[i][1]=dp[i-1][0]; //最高位含有2
dp[i][2]=dp[i-1][2]*10+dp[i-1][1]+dp[i-1][0]; //第一个式子说明低位含有不吉利数字,第二个说明
//次高位含有2,最高位为6,第三个式子说明首位为4
// printf("%d\t%d\t%d\n",dp[i][0],dp[i][1],dp[i][2]); //验证使用,dp[i][0]和dp[i][2]表示最大可能的位数
//例如输入1 100,此时dp[i][0]+dp[i][2]=100
}
}
int solve(int n)
{
int ans=0,sum=n,len=0,a[10];//ans为不符合题意的
while(n) //把该数逐位存到数组中
{
a[++len]=n%10;
n/=10;
}
a[len+1]=0; //讨论的时候需要用到i+1位
bool flag=0;
L(i,len,1)
{
ans+=dp[i-1][2]*a[i];//先对前i-1位即低位的不吉利数字进行统计
if(flag) //见上题分析
ans+=dp[i-1][0]*a[i];
if(!flag&&a[i]>4)
ans+=dp[i-1][0];//此时最高位为4,其余位都为吉利数字
if(!flag&&a[i]>6)
ans+=dp[i-1][1]; //次高位数字为2
if(!flag&&a[i+1]==6&&a[i]>2)
ans+=dp[i][1]; //次高位数字为2,此时i为次高位
if(a[i+1]==6&&a[i]==2||a[i]==4) //不吉利数字存在时,flag记为1
flag=1;
}
return sum-ans; //统计的个数
}
int main()
{
Init();
int n,m;
while(cin>>n>>m,n&&m)
{
cout<<solve(m+1)-solve(n)<<endl;
//因为solve函数中并没有考虑m是不是不幸数的情况,所以m+1只算了1~m,而l只算了1~n-1,这两者相减才是正确答案
}
}
[SCOI2009]windy数
Time Limit:1000MS Memory Limit:165536K
Total Submit:162 Accepted:74Description
windy定义了一种windy数。
不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。
windy想知道,在A和B之间,包括A和B,总共有多少个windy数?Input
包含两个整数,A B。
Output
一个整数。
Sample Input
【输入样例一】 1 10 【输入样例二】 25 50
Sample Output
【输出样例一】 9 【输出样例二】 20 【数据规模和约定】 20%的数据,满足 1 <= A <= B <= 1000000 。 100%的数据,满足 1 <= A <= B <= 2000000000 。
- #include<iostream>
- #include<cstring>
- #include<queue>
- #include<cstdio>
- #include<cmath>
- #include<algorithm>
- #define N 100005
- #define inf 1<<29
- #define MOD 9973
- #define LL long long
- #define eps 1e-7
- #define zero(a) fabs(a)<eps
- #define equal(a,b) zero(a-b)
- using namespace std;
- int dp[15][10];
- //dp[i][j]表示考虑i位的数中,最高为j的windy数
- void Init(){
- memset(dp,0,sizeof(dp));
- for(int i=0;i<=9;i++)
- dp[1][i]=1;
- for(int i=2;i<=10;i++){
- for(int j=0;j<10;j++){
- for(int k=0;k<10;k++)
- if(abs(j-k)>=2)
- dp[i][j]+=dp[i-1][k];
- }
- }
- }
- int slove(int n){
- int len=0,bit[15];
- while(n){
- bit[++len]=n%10;
- n/=10;
- }
- bit[len+1]=0;
- int ans=0;
- //先把长度为1至len-1计入
- for(int i=1;i<len;i++)
- for(int j=1;j<10;j++)
- ans+=dp[i][j];
- //确定最高位
- for(int j=1;j<bit[len];j++)
- ans+=dp[len][j];
- for(int i=len-1;i;i--){
- for(int j=0;j<bit[i];j++)
- if(abs(j-bit[i+1])>=2)
- ans+=dp[i][j];
- //如果高位已经出现非法,直接退出
- if(abs(bit[i]-bit[i+1])<2)
- break;
- }
- return ans;
- }
- int main(){
- Init();
- int l,r;
- while(scanf("%d%d",&l,&r)!=EOF)
- printf("%d\n",slove(r+1)-slove(l));
- return 0;
- }