J. Periodic Ruler题解

J. Periodic Ruler

随便拉了个四星的比赛,然后就稀碎了....
被这个题给干烂了...吐了...
这个题一直很不理解题意,让我再简述下题意吧。
在一个坐标轴上,每个点都有一个颜色。颜色的编号最多就是1到100.其次还有一个最小周期T,每个颜色都满足这个周期,即\(c_i=c_{i+T}\).现给定你若干个点的坐标和他们的颜色。问所有不满足的T的和。没有颜色的坐标你可以随便染任何颜色。
首先考虑周期T的影响,就想到同余,也就是说在0-T-1的余数中,每个余数只能被一种颜色占领。先考虑已有的点中,若两个点的颜色不同,则说明周期T中,他们不能处于同一个余数,这个很容易推到T是\(|x_i-x_j|\)的因子的时候,他们处于同一个余数。所以我们可以\(O(n^2)\)枚举所有的点对,再\(\sqrt{max(xi)}\)枚举其因子即可。剩下的情况就是所有颜色相同的点在同一个余数中,颜色不同的点不在一个余数中。但发现这个题的第二个样例都过不去,因为可能你的周期T不是最小的正周期。考虑什么时候你的周期T不是最小的正周期,考虑若你的周期T的所有余数系没有被填满的话,那么剩下的没有颜色的余数系,我们可以染任意的颜色,考虑这种情况下,能不能被更小的T所代替。考虑什么情况下一个T能被另一个更小的t所代替,必须满足这两个T,t形成的序列是相同。那么也就必须保证,T的余数系中能够被t的余数系填满并延伸得到。这里说复杂了,其实就是t必须是T的因子。且,T的余数系按照t分成若干段,必须是相同的。这样的话,才能被小t代替。但我们考虑刚才的情况,我们有的颜色没有涂满,我们完全可以让这个点和之前对应的点不同,构造一个使得T合法的情况。那么剩下的情况就是一个T的余数系被填满了,那我们就枚举一下它的因子,看当前T能否被它的因子代替即可。这里注意到,因为给到的点只有50个,所以能被代替的T最大是50,因为我们需要满足他的余数系被填满。那这个复杂度就为\(O(n^3)\).

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=110;
int x[N],c[N],n,vis[N];
set<int>s;

inline bool check1(int T)
{
    for(int i=0;i<T;++i) if(!vis[i]) return false;
    return true;
}

inline bool check2(int T,int t)
{
    for(int i=0;i<T;++i)
    {
        if(vis[i]!=vis[i%t]) return false;
    }
    return true;
}

int main()
{
//    freopen("1.in","r",stdin);
    scanf("%d",&n);
    for(int i=1;i<=n;++i) scanf("%d%d",&x[i],&c[i]);
    for(int i=1;i<=n;++i)//处理颜色不同的点造成的不合法的情况。 
        for(int j=i+1;j<=n;++j)
        {
            if(c[i]!=c[j])
            {
                int sx=abs(x[i]-x[j]);
                for(int k=1;k<=sqrt(sx);++k)
                {
                    if(sx%k==0)  
                    {
                        s.insert(k);
                        s.insert(sx/k);   
                    }
                }
            }
        }
    for(int T=1;T<=50;++T)//枚举所有可能被替代的T。 
    {
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=n;++i)
        {
            int d=((x[i]%T)+T)%T;
            vis[d]=c[i];
        }
        if(!check1(T)) continue;//没被填满一定不能被替代。
        for(int j=1;j<T;++j)//判断T能否被j替代。 
        {
            if(T%j==0&&check2(T,j)) 
            {
                s.insert(T);
                break;
            } 
        } 
    }    
    ll ans=0,cnt=0;
    for(auto z:s)  ans+=z,cnt++;
    printf("%lld %lld\n",cnt,ans);
    return 0;
} 
原文地址:https://www.cnblogs.com/gcfer/p/15520613.html