題目鏈接
D. Three Integers
題意:給 a b c 你現在可以對這三個數進行+1 -1 操作 問最少操作後使得 a整除b b整除c
做法:暴力枚舉 a和b 就可以了,注意範圍 容易被hack
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=2e5+10;
int n,m;
ll a,b,c;
ll A,B,C;
ll mx;
void cal(int i,int j,int k)
{
int t=abs(a-i)+abs(b-j)+abs(k-c);
if(t<mx){
mx=t;
A=i,B=j,C=k;
}
}
int main()
{
int _;cin>>_;while(_--)
{
scanf("%lld%lld%lld",&a,&b,&c);
mx=0x3f3f3f3f3f3f3f3f;
for(ll i=1;i<=2e4;++i){
for(ll j=i;j<=2e4;j+=i){
ll x=i,y=j,z=c/y*y;
if(z>=y) cal(x,y,z);
z=(c/y+1)*y;
cal(x,y,z);
}
}
printf("%lld\n",mx);
printf("%lld %lld %lld\n",A,B,C);
}
}
E. Construct the Binary Tree
題意:輸入n d 代表樹的n個節點,每個節點在樹上都有一個深度,現在要你構造二叉樹 使得所有節點的度之和等於d。
不存在輸出NO
思路:思路很簡單,先構造一條單鏈,然後可以考慮從最底下 或者從最上面 取一個點往上移,我這裏是從上面選一個點。
代碼參考 來自 jiufeng 的提交代碼
就是怎麼模擬寫比較的複雜。
#include<bits/stdc++.h>
#define LL long long
#define PB push_back
#define POP pop_back()
#define PII pair<int,int>
#define ULL unsigned long long
using namespace std;
const int INF=0x3f3f3f3f;
const double pi=acos(-1),eps=1e-10;
const int maxn=1<<17;
const int N=5e3+10,M=N*40;
int n,d;
int fa[N];
int son[N];
int de[N];//某層的空置位
int dp[N];//dp[i]: i節點在dp[i]層
int main()
{
de[1]=1;
int t;
cin>>t;
while(t--){
scanf("%d%d",&n,&d);
memset(de,0,sizeof(de));
de[1]=1;
int s=0;
for(int i=1;i<=n;i++)s+=i-1;//一條鏈
int now=1;
for(int i=1;i<=n;i++){
dp[i]=dp[i-1]+1;//下一個節點在i-1的下一層
de[dp[i]]--;//單鏈 去掉這層的一個空置位
if(s-(n-i+1)>=d){//i節點往上跳一層,後面的全部往上跳一層,所以是n-i+1
//printf("i:%d n-i+1:%d d:%d\n",i,n-i+1,d);
if(de[dp[i]-1]){//因爲是往上跳一層,那麼看上一層的空置位是否有
s-=(n-i+1);
de[dp[i]-1]--;//掛在dp[i]-1 層上,所以de[dp[i]-1]的空置位減一
de[dp[i]]++;//dp[i]層的空置位+1 抵消掉32行的減一
dp[i]--;//i節點成功到達 上一層
}
}
de[dp[i]+1]+=2;
//cout<<s<<' '<<(n-i+1)<<' '<<dp[i]<<' '<<de[dp[i]+1]<<' '<<de[dp[i]]<<endl;
}
//cout<<s<<endl;
if(s!=d){
printf("NO\n");
continue;
}
int flag=1;
memset(son,0,sizeof(son));
for(int i=2;i<=n;i++){
fa[i]=0;
for(int j=1;j<i;j++){
if(son[j]<2&&dp[i]==dp[j]+1){
son[j]++;
fa[i]=j;
break;
}
}
if(fa[i]==0){
flag=0;break;
}
}
if(flag==0){
printf("NO\n");
}
else printf("YES\n");
for(int i=2;i<=n;i++)printf("%d ",fa[i]);printf("\n");
}
return 0;
}
/*
1
6 7
0 0 0 0 0 0
0 1 0 3 0 1
2 9 1 2 1 2
8 7 1 3 4 3
1 0 2 2 7 7
0 1 0 0 1 0
0 0 0 0 0 0
*/
F. Moving Points
題意:給定n個位置xi 以及n個速度vi 位置變化爲x=vi*t+xi,現在要你求兩兩點距離和最小,這題容易讀成 所有點的t是一致,其實不然 每個點的時間是不一樣的,而且每對點的時間也是不一樣的。
相當於是求任意兩個點最近的距離時的距離和
做法:將x從大到小排個序,按照v 離散化在線段樹上查找 x比自己小 v 比自己大的點,因爲這些點可以跟這個點重合。
那麼答案 就是先求所有點對的距離和-能重合的距離點對距離和
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
struct node
{
ll x,v;
}a[N];
ll X[N],len;
int n;
bool cmp(node a,node b)
{
return a.x<b.x;
}
int getid(ll x)
{
return lower_bound(X+1,X+1+len,x)-X;
}
ll ans,num,x1,sum;
ll s1[4*N],s2[4*N];
void up(int id,int l,int r,int pos,ll val)
{
if(l==r){
s1[id]+=val;
s2[id]++;
return ;
}
int mid=l+r>>1;
if(pos<=mid) up(id<<1,l,mid,pos,val);
else up(id<<1|1,mid+1,r,pos,val);
s1[id]=s1[id<<1]+s1[id<<1|1];
s2[id]=s2[id<<1]+s2[id<<1|1];
}
void qu(int id,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr){
sum+=s1[id];
num+=s2[id];
return ;
}
int mid=l+r>>1;
if(ql<=mid) qu(id<<1,l,mid,ql,qr);
if(qr>mid) qu(id<<1|1,mid+1,r,ql,qr);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%lld",&a[i].x);
for(int i=1;i<=n;++i) {
scanf("%lld",&a[i].v);
X[++len]=a[i].v;
}
sort(X+1,X+1+len);
len=unique(X+1,X+1+len)-X-1;
sort(a+1,a+1+n,cmp);
ans=0,num=1,x1=a[1].x,sum=0;
for(int i=2;i<=n;++i){
ans+=num*(a[i].x-x1)-sum;
sum+=a[i].x-x1;
num++;
}
//printf("ans:%lld\n",ans);
num=0,sum=0;
for(int i=1;i<=n;++i){
a[i].v=getid(a[i].v);
if(i==1){
up(1,1,len,a[i].v,a[i].x-x1);
continue;
}
num=0,sum=0;
if(a[i].v<len) qu(1,1,len,a[i].v+1,len);
ans-=(num*(a[i].x-x1)-sum);
up(1,1,len,a[i].v,a[i].x-x1);
}
printf("%lld\n",ans);
}