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;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM