Codeforces | CF1029D 【Concatenated Multiples】

\(qwq\)昨天晚上\(Div.3\)过了这道题...早上交了\(1A\)...看在\(CF\)\(hack\)的情况并不乐观而且也没人来交这题的份上...我决定发一篇题解帮\((zhuang)\)\((yi)\)\((bo)\)\((x)\)
题目大意:给出\(n\)个数\(a_1,a_2,\dots,a_n\)\(k\),求对于任意的两个数\(a_i,a_j(i\neq j)\),使得两数连接起来组成的新数(如\(12\)\(3456\)连接组成\(123456\))是\(k\)的倍数的选定方式共有多少种.
很显然检验所有的组合并不现实,一共有\(n\times (n-1)\)个新数组成方法(n方乱搞绝对T飞),所以显然需要用一些特\((qi)\)\((ji)\)\((yin)\)\((qiao)\)来搞定这道题.
利用这是一道数论题的性质,显然涉及到整除可以从余数的角度考虑(这还用想吗),考虑到题目上拼接的操作对余数的影响,我们可以对所有的\(a_1,a_2,\dots,a_n\)进行预处理,只需要找到合适的\(i,j(i\neq j)\)使得\(a_i\times (\lfloor log_{10}a_j\rfloor+1)+a_j=0(mod\ k)\)即可.
所以只需找出能与\(a_i\)组成\(k\)的倍数的\(a_j\)个数并累加即可,个数由预处理得到.
预处理在本题中显得尤为重要,对于每一个数\(a_i\)都可以前接\(a_j\),由于连接操作对前数的余数影响取决于后数的位数,故我们需要判断\(a_i\)的位数下对应能与\(a_i\)余数加和成为\(k\)的倍数的数的个数,所以预处理的内容就是后接\(m(m\in [1,10])\)位数后各余数对应数字的个数(表达能力掉线...感性理解一下)
梳理一下思路:先对所有的\(a_1,a_2,\dots,a_n\),处理每个数后接\(m(m\in [1,10])\)位数后的余数情况(在此选用\(map\)存储...毕竟余数值域是\([0,10^9-1]\)...处理对应\(map\)中后接\(m\)位时的余数作为下标的值\(+1\)即可统计个数),同时考虑到这样做有可能把\(a_i\)后接\(a_i\)的情况记入答案,所以在累加后特判一下\(a_i\)后接\(a_i\)的情况是否合法,合法时将\(ans--\)去重.
下面放代码\(\downarrow \downarrow \downarrow\)...如果实在理解不了的话...我也没什么办法惹(逃)

#include<cstdio>//CF1029D
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<map> 

using namespace std;

map<int,int>mp[11];

const int N=2e5+5;

const long long shi[11]={1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000,10000000000};

int ws(int u){
	return (int)log10(u)+1;
}

int n,k,a[N],mo[N];

long long ans;

int main(){
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		mo[i]=a[i]%k;
	} 
	for(int i=1;i<=n;i++){
		for(int j=1;j<=10;j++){
			mp[j][(int)(((shi[j]%k)*mo[i])%k)]++;
		}
	}
	for(int i=1;i<=n;i++){
		int w=ws(a[i]);
		ans+=mp[w][(k-mo[i])%k];
		if((int)((((shi[w]%k)*mo[i])%k)+mo[i])%k==0){
			ans--;
		}
	}
	printf("%lld\n",ans);
	return 0;
}

小小卡了一下常数刚好跑过\(qwq\)...生死速度就差\(35ms\)(逃)

\(update1:(20180828)\)
由于本题毒瘤卡常卡的厉害...上面代码还是有可能会T(都怪CF评测机...脸黑就是过不了(逃))...所以再放一个卡了常数的代码...亲测\(1887ms\)跑过...应该算是比较保险了...

#include<cstdio>//CF1029D
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<map> 

using namespace std;

map<int,int>mp[11];

const int N=2e5+5;

int ws(int u){
	return (int)log10(u)+1;
}

int n,k,a[N],mo[11][N];

long long ans;

int main(){
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		mo[0][i]=a[i]%k;
		for(int j=1;j<=10;j++){
			mo[j][i]=(int)(((long long)mo[j-1][i]*10)%k);
		}
	} 
	for(int i=1;i<=n;i++){
		for(int j=1;j<=10;j++){
			if(mo[j][i]){
				mp[j][mo[j][i]]++;
			}
			else{
				mp[j][0]++;
			}
		}
	}
	for(int i=1;i<=n;i++){
		int w=ws(a[i]);
		if(mo[0][i]){
			ans+=mp[w][k-mo[0][i]];
		}
		else{
			ans+=mp[w][0];
		}
		if((mo[w][i]+mo[0][i])%k==0){
			ans--;
		}
	}
	printf("%lld\n",ans);
	return 0;
}
posted @ 2018-08-25 11:59  __BLUESKY007  阅读(1090)  评论(0编辑  收藏  举报