生活随笔
收集整理的這篇文章主要介紹了
Codeforces Round #661 (Div. 3)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
A - Remove Smallest
排個序,如果相鄰的數大于一就不滿足題意
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#define debug(x) cout<<#x<<": "<<x<<" "
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std
;
typedef long long ll
;
const int N
=110;
int a
[N
];
int main()
{IO
;int T
;cin
>>T
;while(T
--){int n
;cin
>>n
;for(int i
=0;i
<n
;i
++) cin
>>a
[i
];sort(a
,a
+n
);bool ok
=1;for(int i
=0;i
<n
-1;i
++)if(a
[i
+1]>a
[i
]+1) {ok
=0;break;}if(ok
) cout
<<"YES"<<endl
;else cout
<<"NO"<<endl
;}return 0;
}
B - Gifts Fixing
禮物最終個數肯定是最小的那個。每個禮物減小到最少的那個,注意可以同時減少兩種禮物。
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#define debug(x) cout<<#x<<": "<<x<<" "
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std
;
typedef long long ll
;
const int N
=110;
ll a
[N
],b
[N
];
int main()
{IO
;int T
;cin
>>T
;while(T
--){int n
;cin
>>n
;ll mina
=2e9;ll minb
=2e9;for(int i
=0;i
<n
;i
++) {cin
>>a
[i
];mina
=min(mina
,a
[i
]);}for(int i
=0;i
<n
;i
++){cin
>>b
[i
];minb
=min(minb
,b
[i
]);}ll res
=0;for(int i
=0;i
<n
;i
++) res
+=max(a
[i
]-mina
,b
[i
]-minb
);cout
<<res
<<endl
;}return 0;
}
C - Boats Competition
枚舉+雙指針
由于體重非常小,兩兩配對的體重和也很小,直接暴力枚舉兩兩體重和w。現在問題轉化成原序列找出兩個數的和等于w,雙指針。
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#define debug(x) cout<<#x<<": "<<x<<" "
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std
;
typedef long long ll
;
const int N
=110;
int a
[N
],n
;
int main()
{IO
;int T
;cin
>>T
;while(T
--){cin
>>n
;for(int i
=1;i
<=n
;i
++) cin
>>a
[i
];if(n
==1) {cout
<<0<<endl
;continue;}sort(a
+1,a
+n
+1);int res
=0,mx
=0;for(int w
=a
[1]+a
[2];w
<=a
[n
-1]+a
[n
];w
++){int cnt
=0;for(int i
=1,j
=n
;i
<j
;i
++){while(j
>i
&&a
[i
]+a
[j
]>w
) j
--;if(j
<=i
) break; if(a
[i
]+a
[j
]==w
) cnt
++,j
--;}res
=max(res
,cnt
);}cout
<<res
<<endl
;}return 0;
}
D - Binary String To Subsequences
貪心+二分
貪心:如果該位是1那么找一個末尾是0的序列放進去如果不存在那么新添一組
比如目前有五組0 0 1 1 1分別表示該組最后一個字符是0或者1,如果該位是1我們就二分出最后一個0,pos=2,組別表示變成0 1 1 1 1。如果該位使0我們二分處第一個1的位置,pos=3,組別表示變成0 0 0 1 1,這樣操作可以發現組別表示的序列始終是有序的,保證時間復雜度為O(nlogn)O(nlogn)O(nlogn)。
好像有O(n)O(n)O(n)的做法奈何wctl,寫題的時候只想到這個做法。
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#define debug(x) cout<<#x<<": "<<x<<" "
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
using namespace std
;
typedef long long ll
;
const int N
=200010;
int pos
[N
],a
[N
];
int main()
{IO
;int T
;cin
>>T
;while(T
--){int n
;string s
;cin
>>n
>>s
;int cnt
=1;a
[1]=s
[0]-'0';pos
[0]=1;for(int i
=1;i
<n
;i
++){int t
=s
[i
]-'0';if(t
){int l
=1,r
=cnt
;while(l
<r
){int mid
=l
+r
+1>>1;if(a
[mid
]<=0) l
=mid
;else r
=mid
-1;}if(a
[l
]==0){a
[l
]=1;pos
[i
]=l
;}else {a
[++cnt
]=1;pos
[i
]=cnt
;}}else{int l
=1,r
=cnt
;while(l
<r
){int mid
=l
+r
>>1;if(a
[mid
]>=1) r
=mid
;else l
=mid
+1;}if(a
[l
]==1){a
[l
]=0;pos
[i
]=l
;}else {a
[++cnt
]=0;pos
[i
]=cnt
;}}}cout
<<cnt
<<endl
;for(int i
=0;i
<n
;i
++) cout
<<pos
[i
]<<" ";cout
<<endl
;}return 0;
}
這次做了4個題,差一點做出了E1。
E1 - Weights Division (easy version)
我沒想到這次我不在意的點就是這題的關鍵的!!!
先dfs一下把從根節點到每個葉子節點每條邊跑的次數記錄一下,記作cnt[i],如果該邊邊權為w[i]如果把這條邊砍一半,那么總的路程減小(w[i]-w[i]/2)*cnt[i],顯然貪心,用個優先隊列(按照減小的多優先級高)維護一下就行了。
坑點:很容易想到按照w[i]*cnt[i]排序,不過這題下取整導致問題不斷。(我做的時候想這題應該不會那么麻煩,就圖個省事結果。。。)
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#define debug(x) cout<<#x<<": "<<x<<" "
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<queue>
#include<vector>
using namespace std
;
typedef long long ll
;
const int N
=100010,M
=400010;
int h
[N
],e
[M
],ne
[M
],idx
;
ll w
[M
],limit
,res
;
int n
,d
[N
],cnt
[M
];
struct node
{ll w
;int num
;bool operator <(const node
&o
)const{ll sub1
=(w
-w
/2)*num
;ll sub2
=(o
.w
-o
.w
/2)*o
.num
;return sub1
<sub2
;}
};
priority_queue
<node
> q
;void add(int a
,int b
,ll c
)
{e
[idx
]=b
;w
[idx
]=c
;ne
[idx
]=h
[a
];h
[a
]=idx
++;d
[b
]++;
}
int dfs(int u
,int fa
)
{int lcnt
=0;for(int i
=h
[u
];i
!=-1;i
=ne
[i
]){int j
=e
[i
];if(j
==fa
) continue;cnt
[i
]+=(d
[j
]==1);cnt
[i
]+=dfs(j
,u
);lcnt
+=cnt
[i
];}return lcnt
;
}
void init()
{for(int i
=0;i
<=n
;i
++) h
[i
]=-1,d
[i
]=0,cnt
[i
]=0,cnt
[i
+n
]=0;idx
=res
=0;while(q
.size()) q
.pop();
}
int main()
{IO
;int T
;cin
>>T
;while(T
--){cin
>>n
>>limit
;init();for(int i
=1;i
<n
;i
++){int a
,b
;ll c
;cin
>>a
>>b
>>c
;add(a
,b
,c
);add(b
,a
,c
);}dfs(1,-1);for(int i
=0;i
<2*n
-2;i
+=2) {q
.push({w
[i
],cnt
[i
]+cnt
[i
+1]});res
+=w
[i
]*(cnt
[i
]+cnt
[i
+1]);}ll ans
=0;while(res
>limit
){auto t
=q
.top();q
.pop();q
.push({t
.w
/2,t
.num
});res
-=1ll*(t
.w
-t
.w
/2)*t
.num
;ans
++;}cout
<<ans
<<endl
;}return 0;
}
E2 - Weights Division (hard version)
E1砍邊都是花費1代價,而E2就是有些邊砍一半需要花費1代價有些2代價。顯然我們考慮用兩個優先隊列維護q1,q2,q1維護花費1代價的 q2維護花費2代價的。仍然貪心。每次考慮花費1代價砍邊,如果發現花兩次1代價減小的路程小于直接花費2代價砍邊減小的路程,那么就直接花費2代價砍邊。
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#define debug(x) cout<<#x<<": "<<x<<" "
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<queue>
#include<vector>
using namespace std
;
typedef long long ll
;
const int N
=100010,M
=200010;
int h
[N
],e
[M
],ne
[M
],idx
,cost
[M
];
ll w
[M
],limit
,res
;
int n
,d
[N
],cnt
[M
];
struct node
{ll w
;int num
;bool operator <(const node
&o
)const{ll sub1
=(w
-w
/2)*num
;ll sub2
=(o
.w
-o
.w
/2)*o
.num
;return sub1
<sub2
;}
};
priority_queue
<node
> q1
,q2
;
void add(int a
,int b
,ll c
,int coin
)
{e
[idx
]=b
;w
[idx
]=c
;cost
[idx
]=coin
;ne
[idx
]=h
[a
];h
[a
]=idx
++;d
[b
]++;
}
int dfs(int u
,int fa
)
{int lcnt
=0;for(int i
=h
[u
];i
!=-1;i
=ne
[i
]){int j
=e
[i
];if(j
==fa
) continue;cnt
[i
]+=(d
[j
]==1);cnt
[i
]+=dfs(j
,u
);lcnt
+=cnt
[i
];}return lcnt
;
}
void init()
{for(int i
=0;i
<=n
;i
++) h
[i
]=-1,d
[i
]=0,cnt
[i
]=0,cnt
[i
+n
]=0;idx
=res
=0;while(q1
.size()) q1
.pop();while(q2
.size()) q2
.pop();q1
.push({0,0}),q1
.push({0,0}),q2
.push({0,0});
}
int main()
{IO
;int T
;cin
>>T
;while(T
--){cin
>>n
>>limit
;init();for(int i
=1;i
<n
;i
++){int a
,b
,coin
;ll c
;cin
>>a
>>b
>>c
>>coin
;add(a
,b
,c
,coin
);add(b
,a
,c
,coin
);}dfs(1,-1);for(int i
=0;i
<2*n
-2;i
+=2) {if(cost
[i
]==1) q1
.push({w
[i
],cnt
[i
]+cnt
[i
+1]});else q2
.push({w
[i
],cnt
[i
]+cnt
[i
+1]});res
+=w
[i
]*(cnt
[i
]+cnt
[i
+1]);}ll ans
=0;while(res
>limit
){auto a
=q1
.top();q1
.pop();auto b
=q1
.top();q1
.pop();auto c
=q2
.top();q2
.pop();ll suba
=(a
.w
-a
.w
/2)*a
.num
;ll subb
=max((a
.w
/2-a
.w
/4)*a
.num
,(b
.w
-b
.w
/2)*b
.num
);ll subc
=(c
.w
-c
.w
/2)*c
.num
;if(res
-suba
<=limit
) {ans
++;break;}else {if(suba
+subb
<=subc
){res
-=subc
;q1
.push(a
),q1
.push(b
);q2
.push({c
.w
/2,c
.num
});ans
+=2;}else{res
-=suba
;q1
.push(b
),q1
.push({a
.w
/2,a
.num
});q2
.push(c
);ans
++;}}}cout
<<ans
<<endl
;}return 0;
}
注意:每次只考慮花費1代價砍邊
我在寫的時候寫了一份每次考慮花費2代價砍邊。比較兩次1代價和一次2代價減小的路程嗎,這樣貪心其實不正確,非常dt。
下面代碼是錯誤的貪心思路每次考慮花費2代價砍邊
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#define debug(x) cout<<#x<<": "<<x<<" "
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<queue>
#include<vector>
using namespace std
;
typedef long long ll
;
const int N
=100010,M
=400010;
int h
[N
],e
[M
],ne
[M
],idx
,cost
[M
];
ll w
[M
],limit
,res
;
int n
,d
[N
],cnt
[M
];
struct node
{ll w
;int num
;bool operator <(const node
&o
)const{ll sub1
=(w
-w
/2)*num
;ll sub2
=(o
.w
-o
.w
/2)*o
.num
;return sub1
<sub2
;}
};
priority_queue
<node
> q1
,q2
;void add(int a
,int b
,ll c
,int coin
)
{e
[idx
]=b
;w
[idx
]=c
;cost
[idx
]=coin
;ne
[idx
]=h
[a
];h
[a
]=idx
++;d
[b
]++;
}
int dfs(int u
,int fa
)
{int lcnt
=0;for(int i
=h
[u
];i
!=-1;i
=ne
[i
]){int j
=e
[i
];if(j
==fa
) continue;cnt
[i
]+=(d
[j
]==1);cnt
[i
]+=dfs(j
,u
);lcnt
+=cnt
[i
];}return lcnt
;
}
void init()
{for(int i
=0;i
<=n
;i
++) h
[i
]=-1,d
[i
]=0,cnt
[i
]=0,cnt
[i
+n
]=0;idx
=res
=0;while(q1
.size()) q1
.pop();while(q2
.size()) q2
.pop();
}
int main()
{IO
;int T
;cin
>>T
;while(T
--){cin
>>n
>>limit
;init();for(int i
=1;i
<n
;i
++){int a
,b
,coin
;ll c
;cin
>>a
>>b
>>c
>>coin
;add(a
,b
,c
,coin
);add(b
,a
,c
,coin
);}dfs(1,-1);for(int i
=0;i
<2*n
-2;i
+=2) {if(cost
[i
]==1) q1
.push({w
[i
],cnt
[i
]+cnt
[i
+1]});else q2
.push({w
[i
],cnt
[i
]+cnt
[i
+1]});res
+=w
[i
]*(cnt
[i
]+cnt
[i
+1]);}q1
.push({0,0}),q1
.push({0,0}),q2
.push({0,0});ll ans
=0;while(res
>limit
){auto a
=q1
.top();q1
.pop();auto b
=q1
.top();q1
.pop();auto c
=q2
.top();q2
.pop();ll suba1
=(a
.w
-a
.w
/2)*a
.num
;ll suba2
=(a
.w
/2-a
.w
/4)*a
.num
;ll subb
=(b
.w
-b
.w
/2)*b
.num
;ll subc
=(c
.w
-c
.w
/2)*c
.num
;if(res
-suba1
<=limit
) {ans
++;break;}else if(res
-suba1
-max(suba2
,subb
)<=limit
||res
-subc
<=limit
) {ans
+=2;break;}else if(res
-suba1
-subc
<=limit
) {ans
+=3;break;}else {if(suba2
>subb
){if(suba1
+suba2
>subc
){res
-=suba1
+suba2
;q1
.push(b
),q1
.push({a
.w
/4,a
.num
});q2
.push(c
);}else{res
-=subc
;q1
.push(a
),q1
.push(b
);q2
.push({c
.w
/2,c
.num
});}}else{if(suba1
+subb
>subc
){res
-=suba1
+subb
;q1
.push({b
.w
/2,b
.num
}),q1
.push({a
.w
/2,a
.num
});q2
.push(c
);}else{res
-=subc
;q1
.push(a
),q1
.push(b
);q2
.push({c
.w
/2,c
.num
});}}ans
+=2;}}cout
<<ans
<<endl
;}return 0;
}
嘻嘻還是div3能上一點分QvQ,希望今天div2掉少點分(div2日常掉分)-。-,要加油哦~
總結
以上是生活随笔為你收集整理的Codeforces Round #661 (Div. 3)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。