题意:加减号相同个数,问最大值是多少
思路:sort排序,双指针,加最大减最小,依次进行
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
void solve(){
int n;
cin>>n;
vector<int>q(n);
for (int i = 0; i < n; ++i) {
cin>>q[i];
}
sort(q.begin(),q.end());
int s=0;
for (int l =0,r=n-1 ; l<r ; l++,r--) {
s+=q[r]-q[l];
}
cout<<s<<endl;
}
signed main(){
int t=1;
cin>>t;
while (t--){
solve();
}
}
题意:有一个操作是将某个区间变成相反数,如何能使数组合最大,最大是多少,操作次数最小是多少
思路:0没有影响,把0去掉后,判断负正这样的相邻组合有几个,注意边界判断
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
void solve(){
int n;
cin>>n;
vector<int >q;
int s=0;
for (int i = 0; i <n ; ++i) {
int x;
cin>>x;
if(x!=0)q.push_back(x);
s+= abs(x);
}
q.push_back(1); int cnt=0;
for (int i = 0; i <q.size() ; ++i) {
if(q[i]<0&&q[i+1]>0)cnt++;
}
cout<<s<<' '<<cnt<<endl;
}
signed main(){
int t=1;
cin>>t;
while (t--){
solve();
}
}
题意:一个完全二叉树,求他父亲点的编号的和,包括自己
思路:二叉搜索,/2加即可
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
void solve(){
int n;
cin>>n;
int s=0;
while (n){
s+=n;
n/=2;
}
cout<<s<<endl;
}
signed main(){
int t=1;
cin>>t;
while (t--){
solve();
}
}
题意:一个树,每个叶子节点是一个苹果,问一个节点所对应的苹果和另一个节点所对应的苹果的组合数是多少
思路:本想BFS遍历一下记录节点的父亲,以及标记一下苹果,如何从苹果开始向上还原,父亲都加一,不过复杂度最差可能是n²,因此就爆。后来发现dfs回溯记录即可
代码:
正解(dfs)
#include<bits/stdc++.h>
using namespace std;
//#define int long long
vector<int>a[200005];
int ans[200006];
int dfs(int u,int f){
if(a[u].size()==1&&a[u][0]==f){
ans[u]=1;
return 0;
}
for (auto i:a[u]) {
if(i!=f){
dfs(i,u);
ans[u]=ans[u]+ans[i];
}
}
return 0;
}
void solve(){
int n;
cin>>n;
for (int i = 0; i <= n; ++i) {
a[i].clear();
ans[i]=0;
}
for (int i = 1; i < n; ++i) {
int x,y;
cin>>x>>y;
a[x].push_back(y);
a[y].push_back(x);
}
dfs(1,-1);
int m;
cin>>m;
for (int i = 0; i <m ; ++i) {
int x,y;
cin>>x>>y;
cout<<(long long)ans[x]*ans[y]<<endl;
}
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t=1;
cin>>t;
while (t--){
solve();
}
}
tle(BFS):
#include<bits/stdc++.h>
using namespace std;
//#define int long long
vector<int>a[200005];
int fa[200006];
int ans[200006];
int vis[200006];
void solve(){
int n;
cin>>n;
for (int i = 0; i <= n; ++i) {
a[i].clear();
fa[i]=0;
ans[i]=0;
vis[i]=0;
}
for (int i = 1; i < n; ++i) {
int x,y;
cin>>x>>y;
a[x].push_back(y);
a[y].push_back(x);
}
int m;
cin>>m;
queue<int>q;
q.push(1);
fa[1]=1;
vis[1]=1;
vector<int>apple;
while(!q.empty()){
auto t=q.front();
q.pop();
if(a[t].size()==1&&t!=1){
apple.push_back(t);
}
for (int i = 0; i <a[t].size() ; ++i) {
int g=a[t][i];
if(vis[g]==0){
vis[g]=1;
q.push(g);
fa[g]=t;
}
}
}
// for (int i = 1; i <=n ; ++i) {
// cout<<fa[i]<<' ';
// }
fa[1]=1;
ans[1]=apple.size();
for (int i=0;i<apple.size();i++) {
for (int j = apple[i];j!=1 ; j=fa[j]) {
ans[j]++;
}
}
// for (int i = 1; i <=n ; ++i) {
// cout<<ans[i]<<' ';
// }
// cout<<endl;
while(m--){
int x,y;
cin>>x>>y;
cout<<ans[x]*ans[y]<<endl;
}
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t=1;
cin>>t;
while (t--){
solve();
}
}
题意:一个操作,可以把一个数从0变成1,一共m个区间,n个点,q次操作,问第几次操作即可确定至少有一个区间的1的个数严格大于0的个数
思路:此题操作越多,条件就越容易成立,因此具有二分性,我们可以直接二分操作进行到第几次了,然后暴力,前缀求是否含有这种区间
代码:
#include<bits/stdc++.h>
using namespace std;
//#define int long long
#define PII pair<int,int>
void solve(){
int n,m;
cin>>n>>m;
vector<PII>ve(m+1);
for (int i = 1; i <=m; ++i) {
cin>>ve[i].first>>ve[i].second;
}
int k;
cin>>k;
vector<int>q(k+1);
for (int i = 1; i <=k ; ++i) {
cin>>q[i];
}
int ans=0;
int l=1,r=k;
auto check = [&](int mid) ->bool {
vector<int>sum(n+1);
vector<int>g(n+1);
for (int i = 1; i <=mid ; ++i) {
g[q[i]]++;
}
for (int i = 1; i <=n ; ++i) {
sum[i]=sum[i-1]+g[i];
}
int cnt=0;
for (int i = 1; i <=m ; ++i) {
cnt=sum[ve[i].second]-sum[ve[i].first-1];
if(cnt> ( ve[i].second-ve[i].first+1) / 2)return true;
// int cnt = sum[ve[i].second] - sum[ve[i].first - 1];
// if(cnt > (ve[i].second - ve[i].first + 1) / 2 ) return true;
}
return false;
};
while (l <= r)
{
int mid = l + r >> 1;
if(check(mid)) {
r = mid-1;
ans=mid;
}
else l = mid + 1;
}
if(check(ans)) cout << ans << "\n";
else cout << -1 << "\n";
}
int main(){
int t=1;
cin>>t;
while (t--){
solve();
}
}