题意:有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
*/
要保证:
然后根据 F k = A ∗ B − C ( m o d p ) F_k=A*B-C(mod\ p) Fk=A∗B−C(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;
}