随笔—邀请赛前训— Codeforces Round #330 (Div. 2) B题
题意:
这道英文题的题意稍稍有点复杂。
找长度为n的数字序列有多少种。这个序列可以分为n/k段,每段k个数字。k个数可以变成一个十进制的数Xi。要求对这每n/k个数,剔除Xi可被ai整除的情况,剔除X的第一个数(包括前导0)是bi的情况。问剩下的组合有多少种。
思路:
这题我是一波三折的。首先也没有考虑很多,看着可以暴力模拟过程,我就直接开始敲了,几个for循环敲出来,再把bug调一调和特殊情况考虑考虑,交了之后开始TLE,这时候意识到复杂度太大了,于是开始优化,做了(b[i])*(mmax/10)-1 ~ (b[i]+1)*(mmax/10)-1 的循环范围优化后,后面的案例又超时了,后来觉得应该不能暴力模拟了,注意到一定范围内可以被一个数整除的数的数目是可以通过公式算的,这才用公式直接计算省去了for循环,这才过了题。
#include<cstdio> #include<cstring> #include<iostream> using namespace std; #define MAX(x,y) (((x)>(y)) ? (x) : (y)) #define MIN(x,y) (((x) < (y)) ? (x) : (y)) #define ABS(x) ((x)>0?(x):-(x)) const int inf = 0x7fffffff; const int N=100000+10; const long long mod=1e9+7; int a[N]; int b[N]; int main() { // freopen("out.txt", "w", stdout); int n; int k; cin>>n>>k; int kk=k; long long mmax=1; while(kk--) mmax *= 10; // cout<<mmax; int num=n/k; for(int i=0; i<num; i++) scanf("%d",a+i); for(int i=0; i<num; i++) scanf("%d",b+i); long long ans=1; for(int i=0; i<num; i++) { long long cnt=(mmax-1)/a[i]+1; if(b[i] == 0){ cnt-=(mmax/10-1)/a[i]+1; } else{ cnt=cnt-( ((b[i]+1)*(mmax/10)-1)/a[i]+1 ) + ( ((b[i])*(mmax/10)-1)/a[i]+1 ); } ans=ans*cnt % mod; } cout<<ans<<endl; return 0; }