选一点 B ,使得 ∣ O A − A B ∣ |OA-AB| ∣OA−AB∣为 K 时 A 需要挪动多少单位。那么当OA <= k 时,使AB=0,需要挪动k-OA。当OA>k 时 B 点必须在OA内,此时 OA 分解为a、b之和,那么当OA为奇数时 k = ∣ a − b ∣ k=|a-b| k=∣a−b∣ 为奇数,当OA为偶数时 k = ∣ a − b ∣ k=|a-b| k=∣a−b∣ 为偶数。所以根据 k 的奇偶性改变OA的奇偶性即可。
#include
using namespace std;
int main()
{
int T; cin>>T;
while(T--){
int a,k;
cin>>a>>k;
if(a<=k) cout<<k-a<<"\n";
else {
if((a%2==0&&k%2==0)||(a%2==1&&k%2==1)) cout<<"0\n";
else cout<<"1\n";
}
}
return 0;
}
只有 (2,1) 的结果为2,(1,2)的结果为 -2 ,其余均为 0。所以组成尽量多的(2,1)后,使用 a 中的0、2消耗 b 中的 2,最后剩下的只能和 a 中的 1 匹配,减去即可。
#include
using namespace std;
int main()
{
int T; cin>>T;
while(T--){
LL a,b,c,x,y,z;
cin>>a>>b>>c>>x>>y>>z;
LL ans = min(c,y)*2;
if(c>y) z -= (c-y);
ans -= max(z-a,0)*2;
cout<<ans<<"\n";
}
return 0;
}
题意: 使用以下操作后,判断是否能使给定数组按照非递减排序。操作:设数组中的最小值为M,当 g c d ( a i , b j ) = M gcd(a_i,b_j)=M gcd(ai,bj)=M 时可以交换两数的位置。
思路: 那么让需要交换的两个数都通过最小的数中转交换,此时需要的限制是最弱的,若此时不能成功那么就不会成功了。
#include
using namespace std;
typedef long long LL;
const int N = 2e5+7;
int a[N],b[N];
int main()
{
int T; cin>>T;
while(T--){
int n;
cin>>n;
for(int i=0;i<n;i++){
cin>>a[i];
b[i]=a[i];
}
sort(b,b+n);
int flag=1;
for(int i=0;i<n;i++){
if(a[i]!=b[i]&&__gcd(a[i],b[0])!=b[0]) flag=0;
}
if(flag) cout<<"YES\n";
else cout<<"NO\n";
}
return 0;
}
题意: 给一颗树的 n-1 条边赋值,使得 ∑ i = 1 n − 1 ∑ j = i + 1 n f ( i , j ) \sum\limits_{i=1}^{n-1} \sum\limits_{j=i+1}^n f(i,j) i=1∑n−1j=i+1∑nf(i,j) 最大,其中 f ( u , v ) f(u,v) f(u,v) 代表 u 到 v 的简单路径。
赋值的限制:1、每个权值大于0 。2、n-1 个边权的乘积等于k。3、边权中1的数量尽量少。
其中 k 以 p 个素数因子的形式给出。
思路: 需要求的是所有路径的和,所以我们直接计算每条边经过的次数,然后贪心地给经过次数较多的边以 p 中的较大的值,若 p < n-1,则补1,若 p > n-1,则删去最大的p - (n-2) 个数,用他们的乘积代替。
#include
using namespace std;
typedef long long LL;
const int mod = 1e9+7;
const int N = 2e5+7;
int h[N],e[N*2],ne[N*2],idx;
LL si[N];
void add(int a,int b){
e[idx] = b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int x,int f){
si[x] = 1;
for(int i=h[x];i!=-1;i=ne[i]){
int j = e[i];
if(j==f) continue;
dfs(j,x);
si[x] += si[j]; // 每个子树的大小
}
}
int main()
{
int T; cin>>T;
while(T--){
LL n;
cin>>n;
memset(h,-1,sizeof h);
idx=0;
for(int i=1;i<n;i++){
int x,y;
cin>>x>>y;
add(x,y),add(y,x);
}
vector<LL> pp,ve;
LL p,x;
cin>>p;
for(int i=0;i<p;i++) cin>>x,pp.push_back(x);
for(int i=p;i<n-1;i++) pp.push_back(1);
dfs(1,0);
for(int i=2;i<=n;i++) ve.push_back(si[i]*(n-si[i]));//每条边的两端的节点的个数的乘积既是经过次数
sort(ve.begin(),ve.end());
sort(pp.begin(),pp.end());
while(pp.size()>n-1){ //删去多于n-1的边
LL x = pp.back();pp.pop_back();
LL y = pp.back();pp.pop_back();
pp.push_back(x*y%mod);
}
sort(pp.begin(),pp.end()); //再次排序
LL ans=0;
for(int i=0;i<n-1;i++) ans = (ans + pp[i]*ve[i])%mod;
cout<<ans<<"\n";
}
return 0;
}