Topcoder SRM 640 Div2 1000(巧妙数学题)

Problem Statement

 

A multiset is the same thing as a set, with the difference that a multiset can contain multiple copies of the same element. For example, {1,1,1,2,3} is a multiset that contains three 1s, one 2, and one 3.

The distance between two multisets is the smallest total number of elements we need to erase from them in order to make them equal. For example, the distance between {1,1,2,2,3} and {1,2,2,4} is 3. Note that we can compute distance as follows: For each value, we count its occurrences in the first multiset, we count its occurrences in the second multiset, and we write down the difference between those two counts. The distance is then equal to the sum of all values we wrote down.

If S is a multiset, then (S modulo M) is the multiset of all values (x modulo M) where x belongs to S. For example, if S = {11,12,13,21,22} and M = 10, then (S modulo M) = {1,2,3,1,2} = {1,1,2,2,3}.

You have two multisets called A and B. The first multiset is described by the vector <int>s A and numA. For each valid i, the multiset contains numA[i] copies of the value A[i]. The second multiset is described by the vector <int>s B and numB in the same way.

We are now looking for a positive integer M with the following properties: M must be greater than 1, and the distance between (A modulo M) and (B modulo M) must be as small as possible. Compute and return the smallest possible distance.

Definition

 
Class:TwoNumberGroupsEasy
Method:solve
Parameters:vector <int>, vector <int>, vector <int>, vector <int>
Returns:int
Method signature:int solve(vector <int> A, vector <int> numA, vector <int> B, vector <int> numB)
(be sure your method is public)

Limits

 
Time limit (s):2.000
Memory limit (MB):256

Constraints

-A and B will each contain between 1 and 10 elements, inclusive.
-All elements of A will be distinct.
-All elements of B will be distinct.
-The number of elements in numA will be the same as the number of elements in A.
-The number of elements in numB will be the same as the number of elements in B.
-All elements of A and B will be between 1 and 1,000,000,000, inclusive.
-All elements of numA and numB will be between 1 and 100,000, inclusive.

Examples

0) 
 
{1,2,3,4}
{2,1,1,1}
{5,6,7,8}
{1,1,1,2}
Returns: 2
This input describes the multisets A = {1,1,2,3,4} and B = {5,6,7,8,8}. For M=2, we have (A modulo M) = {0,0,1,1,1} and (B modulo M) = {0,0,0,1,1}. The distance between these two multisets is 2, and that is the best we can get.
1) 
 
{5,7}
{1,1}
{12,14}
{1,1}
Returns: 0
The optimal solution is obtained for M = 7.
2) 
 
{100}
{2}
{1}
{1}
Returns: 1
3) 
 
{1}
{1}
{1}
{1}
Returns: 0
4) 
 
{5}
{1}
{6}
{1}
Returns: 2
5) 
 
{733815053,566264976,984867861,989991438,407773802,701974785,599158121,713333928,530987873,702824160}
{8941,4607,1967,2401,495,7654,7078,4213,5485,1026}
{878175560,125398919,556001255,570171347,643069772,787443662,166157535,480000834,754757229,101000799}
{242,6538,7921,2658,1595,3049,655,6945,7350,6915}
Returns: 7

题意如下:

给两个集合(允许重复元素)S1,S2,定义d为S1,S2的距离,d为S1,S2中不同元素的个数之差的绝对值之和(具体请看题目)。现在需要有一个m,让S1,S2中所有的元素都mod m,得到新的集合S1,S2(具体请看题目),问对于任意的m,得到新的集合S1,S2的距离d,d最小是多少?


设x属于S1, y属于S2,设同余方程x=y(mod m),则x-am=y-bm,转换后得到x-y=(a-b)m,由此可知:在此同余方程下,m一定为x-y的约数。

有一个问题,为什么一定要同余方程呢?请自己思考,x,y同余情况下一定比不同余要优

S1,S2集合个数不超过10个,这是个切入点,枚举所有x,y,得到abs(x-y)当入一个集合D中,将D中元素适当去重,然后枚举D中元素的所有约数放入新集合mod中,再加入一个元素2(一会解释),对于这个新集合mod,每一个元素就是一个m,一定有一个m能使得新的S1,S2的距离d最小。这样子就避免了从1到10^9枚举所有的m,适当的利用同余方程导出的性质排除了很多没必要的m,只关系有意义的m。

为什么要多加一个2呢?看样例3就知道了,适当加一个2,就可以保证类似与样例3的情况不出错啦。

m到底是大于1还是大于等于1呢?根据样例1就知道了,如果m==1,则答案应该是0,但答案是2,所以m>1(题意没描述很清楚)


//Hello. I'm Peter.
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<cctype>
#include<ctime>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double ld;
#define peter cout<<"i am peter"<<endl
#define input freopen("data.txt","r",stdin)
#define randin srand((unsigned int)time(NULL))
#define INT (0x3f3f3f3f)*2
#define LL (0x3f3f3f3f3f3f3f3f)*2
#define gsize(a) (int)a.size()
#define len(a) (int)strlen(a)
#define slen(s) (int)s.length()
#define pb(a) push_back(a)
#define clr(a) memset(a,0,sizeof(a))
#define clr_minus1(a) memset(a,-1,sizeof(a))
#define clr_INT(a) memset(a,INT,sizeof(a))
#define clr_true(a) memset(a,true,sizeof(a))
#define clr_false(a) memset(a,false,sizeof(a))
#define clr_queue(q) while(!q.empty()) q.pop()
#define clr_stack(s) while(!s.empty()) s.pop()
#define rep(i, a, b) for (int i = a; i < b; i++)
#define dep(i, a, b) for (int i = a; i > b; i--)
#define repin(i, a, b) for (int i = a; i <= b; i++)
#define depin(i, a, b) for (int i = a; i >= b; i--)
#define pi acos(-1.0)
#define eps 1e-6
#define MOD 1000000007
#define MAXN
#define N
#define M
class TwoNumberGroupsEasy{
public:
    int solve(vector <int> A, vector <int> numA, vector <int> B, vector <int> numB){
        int len1=gsize(A),len2=gsize(B);
        vector<int>D;D.clear();
        rep(i,0,len1){
            rep(j,0,len2){
                D.pb(abs(A[i]-B[j]));
            }
        }
        sort(D.begin(),D.end());
        unique(D.begin(),D.end());
        vector<int>mod;mod.clear();
        rep(k,0,gsize(D)){
            double to=(double)sqrt((double)D[k]);
            repin(i,1,to){
                if(D[k]%i==0){
                    int t=i;
                    if(t>1) mod.pb(t);
                    t=D[k]/i;
                    if(t>1) mod.pb(t);
                }
            }
        }
        mod.pb(2);
        sort(mod.begin(),mod.end());
        unique(mod.begin(),mod.end());
        int len=gsize(mod);
        int res=INT;
        map<int,int>m1,m2;
        map<int,int>::iterator it;
        rep(k,0,len){
            if(mod[k]<=1) continue;
            m1.clear(),m2.clear();
            rep(i,0,len1){
                int t=A[i]%mod[k];
                m1[t]+=numA[i];
            }
            rep(i,0,len2){
                int t=B[i]%mod[k];
                m2[t]+=numB[i];
            }
            for(it=m1.begin();it!=m1.end();it++){
                int t=it->first;
                int num=it->second;
                m2[t]-=num;
            }
            int rest=0;
            for(it=m2.begin();it!=m2.end();it++){
                rest+=abs(it->second);
            }
            res=min(res,rest);
        }
        return res;
    }
};



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值