2020杭电多校第二场HDU-6763、6768

HDU-6763-Total Eclipse(并查集+思维)

题意:有n个城市,每个城市都有一个亮度。每次选一个连通块,然后把里面的k个城市亮度全部减一,重复这个操作直到所有城市亮度均为0。求最小操作次数

思路:为了保证操作次数最小,所以每次我们选一个最大的连通块,对这个连通块操作x次(x为这个连通中的最小亮度)。x次操作后,这个连通块会断开变成0、2、3、4…个连通块,不过如果继续找连通块去减的话时间复杂度不允许,但因为留下来的亮度不为0的城市都是亮度较大的,所以我们考虑反向操作,先把亮度较大的城市亮度都减到x,然后进行x次操作将亮度都变为0。

具体操作:按亮度大小顺序将点加入集合S,每加入一个点,就把所有已加入点的亮度先减为当前点的亮度。假设已加入点形成sum个连通块,则最小操作次数ans+=sum*(已加入点现在的亮度-当前点的亮度)。然后再维护下连通块的个数。

#include
#include
#include
#include
#include
#include
using namespace std;
#define int long long
const int manx = 1e5 + 10;

int fa[manx],t,n,m,x,y,cou=0;
int head[manx],vs[manx];//vs[i]=1表示点i已经加入集合S
struct node
{
    int w,pos;
} num[manx];
struct edges
{
    int e,bf;
}edge[manx<<2];
inline void add(int s,int e)
{
    edge[cou]=edges{e,head[s]};
    head[s]=cou++;
}
int ffind(int x)
{
    if(fa[x] == x)return x;
    else return fa[x] = ffind(fa[x]);
}
void init()
{
    cou=0;
    memset(head,-1,sizeof head);
    memset(vs,0,sizeof vs);
}
signed main()
{
    scanf("%lld",&t);
    while(t--)
    {
        init();
        scanf("%lld%lld",&n,&m);
        for(int i=1; i<=n; i++)
        {
            scanf("%lld",&num[i].w);
            fa[i]=num[i].pos=i;
        }
        sort(num+1,num+n+1,[](node a,node b){return a.w>b.w;});
        for(int i=1; i<=m; i++)
        {
            scanf("%lld%lld",&x,&y);
            add(x,y);
            add(y,x);
        }
        int ans=0,sum=0,per=num[1].w;
        for(int i=1;i<=n;i++)
        {
            int now=num[i].pos;
            ans+=sum*(per-num[i].w);
            vs[now]=1;
            sum++;
            for(int j=head[now];~j;j=edge[j].bf)
            {
                int net=edge[j].e;
                if(!vs[net])continue;//如果点net还未加入集合S就跳过
                int fnow=ffind(now);
                int fnet=ffind(net);
                if(fnow!=fnet)
                {
                    fa[fnow]=fnet;
                    sum--;//S中的两个连通块可以通过以点now为起点的一条边相连通
                }
            }
            per=num[i].w;
        }
        ans+=per*sum;
        printf("%lld\n",ans);
    }
    return 0;
}
/*
4
4 4
1 2 3 5
1 2
2 3
3 1
2 4
*/

HDU-6763-Total Eclipse(hash)

要保证:
在这里插入图片描述
然后根据 F k = A ∗ B − C ( m o d   p ) F_k=A*B-C(mod\ p) Fk=ABC(mod p)求解

//自然溢出
#include
#include
#include
#include
#include
#include
using namespace std;
#define int unsigned long long
const int manx = 2e6 + 10;
const int mod = 1e9 + 7;

int F[manx];
signed main()
{
    int t,A,B,C,a,b,c,f;
    F[0]=1,F[1]=1;
    for(int i=2;i<=2e6+1;i++)
        F[i]=F[i-1]+F[i-2];
    scanf("%lld",&t);
    while(t--)
    {
        a=b=c=0;
        scanf("%lld",&A);
        for(int i=1;i<=A;i++)
        {
            scanf("%lld",&f);
            if(f)a+=F[i];
        }
        scanf("%lld",&B);
        for(int i=1;i<=B;i++)
        {
            scanf("%lld",&f);
            if(f)b+=F[i];
        }
        scanf("%lld",&C);
        for(int i=1;i<=C;i++)
        {
            scanf("%lld",&f);
            if(f)c+=F[i];
        }
        int temp=a*b-c;
        for(int i=1;i<=2e6+1;i++)
            if(F[i]==temp)
        {
            printf("%lld\n",i);
            break;
        }
    }
    return 0;
}
//双hash
#include
#include
#include
#include
#include
#include
using namespace std;
#define int long long
const int manx = 2e6 + 10;
const int mod = 1e9 + 7;
const int mod2 = 1e7 + 19;

int F[manx],F2[manx];
signed main()
{
    int t,A,B,C,a,b,c,f;
    int a2,b2,c2;
    F[0]=1,F[1]=1;
    F2[0]=1,F2[1]=1;
    for(int i=2;i<=2e6+1;i++)
    {
        (F[i]=F[i-1]+F[i-2])%=mod;
        (F2[i]=F2[i-1]+F2[i-2])%=mod2;
    }
    scanf("%lld",&t);
    while(t--)
    {
        a=b=c=0;
        a2=b2=c2=0;
        scanf("%lld",&A);
        for(int i=1;i<=A;i++)
        {
            scanf("%lld",&f);
            if(f)(a+=F[i])%=mod;
            if(f)(a2+=F2[i])%=mod2;
        }
        scanf("%lld",&B);
        for(int i=1;i<=B;i++)
        {
            scanf("%lld",&f);
            if(f)(b+=F[i])%=mod;
            if(f)(b2+=F2[i])%=mod2;
        }
        scanf("%lld",&C);
        for(int i=1;i<=C;i++)
        {
            scanf("%lld",&f);
            if(f)(c+=F[i])%=mod;
            if(f)(c2+=F2[i])%=mod2;
        }
        int temp=(a*b-c+mod)%mod;
        int temp2=(a2*b2-c2+mod2)%mod2;
        for(int i=1;i<=2e6+1;i++)
            if(F[i]==temp&&F2[i]==temp2)
        {
            printf("%lld\n",i);
            break;
        }
    }
    return 0;
}

你可能感兴趣的:(2020杭电多校第二场HDU-6763、6768)