您的位置:首页 > 理论基础 > 计算机网络

【2015ZUFE新生赛网络同步赛M】【DP 打表 二分】GW I (3) 暴力预处理+分类打表二分查找

2015-12-07 12:21 549 查看
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);}
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1,class T2>inline void gmax(T1 &a,T2 b){if(b>a)a=b;}
template <class T1,class T2>inline void gmin(T1 &a,T2 b){if(b<a)a=b;}
int casenum,casei;
const int TOP=1e7;
int f[TOP+10];
vector<int>a[10];
vector<int>::iterator lft,rgt;
inline int cnt(int x)
{
int p=0;
int odd=0;
int even=0;
while(x)
{
++p;
if(p&1)odd+=x%10;
else even+=x%10;
x/=10;
}
return odd*even;
}
int st[]={1,10,100,1000,10000,100000};
int ed[]={9,99,999,9999,99999,999999};
int w[TOP/10+10][2];
int even,odd;
void table()
{
for(int i=0;i<10;++i)
{
w[i][1]=i;
f[i]=i;
a[i].push_back(i);
}
for(int bit=0;bit<=5;++bit)
{
for(int i=st[bit];i<=ed[bit];++i)
{
int bef=i*10;
for(int j=0;j<10;++j)
{
int now=bef+j;
if(bit<5)
{
w[now][0]=w[i][1];
w[now][1]=w[i][0]+j;
f[now]=f[w[now][0]*w[now][1]];
}
else
{
even=w[i][1];
odd=w[i][0]+j;
f[now]=f[even*odd];
}
a[f[now]].push_back(now);
}
}
}
f[10000000]=0;
a[0].push_back(10000000);
}
int main()
{
table();
scanf("%d",&casenum);
for(casei=1;casei<=casenum;++casei)
{
int l,r,x;
scanf("%d%d%d",&l,&r,&x);
if(x>=10)puts("0");
else
{
lft=lower_bound(a[x].begin(),a[x].end(),l);
rgt=upper_bound(a[x].begin(),a[x].end(),r);
printf("%d\n",rgt-lft);
}
}
return 0;
}
/*
【trick&&吐槽】
暴力出奇迹呀!分情况打表+二分真是好技巧哇!
评测机一变,我这种做法就大概是最优解了!O(1e8)的算法再也没法AC了呢!

【题意】
定义f(x)为——
if(x十进制下奇数位置数值和*x十进制下偶数位置数值和为个位数w,那么return w)
else return f(w);
然后有T(1000)组询问。
对于每组询问,问你[0<=l<=r<=1e7]的区间范围内,有多少个数的f()权值为x。

【类型】
暴力 二分

【分析】
首先,显然x的取值范围是[0,9]。
所以,如果x不是[0,9],直接返回0.
然后,我们发现——
我们可以用O(n)的时间算出[0~n]的f()值,
然后,我们无法记录x==0~9条件下的所有前缀和,因为数据范围太大会爆空间。
然而,这些数的总数也不过只有1e7个,对于f(x)==w,我们把w push_back到vector(x)中
这样对于一个查询区间[l,r],我们可以二分查询>=l和>r的第一个数的下标,两者减一下就是答案啦。

【时间复杂度&&优化】
O(n*k+Tlog())

1,这题数字拆分的复杂度有些大,我们可以通过DP优化
2,我们用数组代替vector的话,时间效率也会大大提高。

*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息