zoukankan      html  css  js  c++  java
  • 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 eq j)),使得两数连接起来组成的新数(如(12)(3456)连接组成(123456))是(k)的倍数的选定方式共有多少种.
    很显然检验所有的组合并不现实,一共有(n imes (n-1))个新数组成方法(n方乱搞绝对T飞),所以显然需要用一些特((qi))((ji))((yin))((qiao))来搞定这道题.
    利用这是一道数论题的性质,显然涉及到整除可以从余数的角度考虑(这还用想吗),考虑到题目上拼接的操作对余数的影响,我们可以对所有的(a_1,a_2,dots,a_n)进行预处理,只需要找到合适的(i,j(i eq j))使得(a_i imes (lfloor log_{10}a_j floor+1)+a_j=0(mod k))即可.
    所以只需找出能与(a_i)组成(k)的倍数的(a_j)个数并累加即可,个数由预处理得到.
    预处理在本题中显得尤为重要,对于每一个数(a_i)都可以前接(a_j),由于连接操作对前数的余数影响取决于后数的位数,故我们需要判断(a_i)的位数下对应能与(a_i)余数加和成为(k)的倍数的数的个数,所以预处理的内容就是后接(m(min [1,10]))位数后各余数对应数字的个数(表达能力掉线...感性理解一下)
    梳理一下思路:先对所有的(a_1,a_2,dots,a_n),处理每个数后接(m(min [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
    ",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
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    C#.Net Winform 应用程序莫名其妙崩溃。
    不小心点击安装了搜狗手机助手,顿时有一种草搜狗全体人员的感觉。
    家乐福张江店班车时刻表
    为什么学习设计模式
    同一端口如何区分不同的Socket
    用命令行CMD .bat 相关操作 如: 创建快捷方式 复制文件等
    C++ 时间获取和时间测量
    get all ODBC drivers 驱动
    命令行 编译C#.NET项目
    如何打开.hlp文件指定的topic
  • 原文地址:https://www.cnblogs.com/--BLUESKY007/p/9533452.html
Copyright © 2011-2022 走看看