A

我们发现满足就是,所以输出就行了,注意特判

CODE

#include <algorithm>
#include <cctype>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstring>
#include <deque>
#include <functional>
#include <list>
#include <map>
#include <iomanip>
#include <iostream>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
using namespace std;
#define int long long
#define I inline
#define ri register int
#define For(i , x , y) for(ri i = x ; i <= y ; ++ i)
#define Next(i , x) for(ri i = head[x] ; i ; i = e[i].nxt)
#define pb(x) push_back(x)
#define lowbit(x) x & -x
I int read() {
    int s = 0 , w = 1; char ch = getchar();
    while(ch < 48 || ch > 57) {if(ch == '-') w = -1; ch = getchar();}
    while(ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48) , ch = getchar();
    return s * w;
}

int n;

signed main() {
    cin >> n;
    if(n == 1) {
        puts("2") ; return 0;
    }   
    cout << n + n - 1 << endl;
    return 0;
}

B

我们发现不变越大时,越小,越大。

这里提供一个乱搞的贪心做法:我们将每一个数转化为二进制,每一位拆开,某一位上的数,预处理前缀和,首先枚举,如果顺序枚举的话肯定会超时,我们枚举二进制下是1的那一位上的那个数列上之后第一个是的位置,作为的位置,不难证明这是正确的。

时间复杂度

CODE

#include <algorithm>
#include <cctype>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstring>
#include <deque>
#include <functional>
#include <list>
#include <map>
#include <iomanip>
#include <iostream>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
using namespace std;
#define int long long
#define I inline
#define ri register int
#define For(i , x , y) for(ri i = x ; i <= y ; ++ i)
#define Next(i , x) for(ri i = head[x] ; i ; i = e[i].nxt)
#define pb(x) push_back(x)
#define lowbit(x) x & -x
I int read() {
    int s = 0 , w = 1; char ch = getchar();
    while(ch < 48 || ch > 57) {if(ch == '-') w = -1; ch = getchar();}
    while(ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48) , ch = getchar();
    return s * w;
}

const int N = 1e5 + 5;
int n , a[N] , to[20][N] , sum[N] , s[21][N] , Ans;

I int calc_and(int l , int r) {
    int res = 0;
    For(i , 0 , 20) {
        if(s[i][r] - s[i][l - 1] == r - l + 1) res += pow(2 , i);
    }
    return res;
}

signed main() {
    //freopen("1.in" , "r" , stdin);
    n = read();
    For(i , 1 , n + 1) {
        if(i <= n) a[i] = read() , sum[i] = sum[i - 1] + a[i];
        For(j , 0 , 20) {
            if( !( (a[i] >> j) & 1 ) && ((a[i - 1] >> j) & 1)) {
                for(int k = i - 1 ; k >= 1 ; -- k) {
                    if(!( (a[k] >> j) & 1 )) break;
                    to[j][k] = i - 1;
                }
            }  
            s[j][i] = s[j][i - 1] + ( (a[i] >> j) & 1 );
        }
    }
    For(i , 1 , n) {
        Ans = max(Ans , a[i] * a[i]);
        For(j , 0 , 20)
            if((a[i] >> j) & 1) {

                Ans = max(Ans , (sum[to[j][i]] - sum[i - 1]) * calc_and(i , to[j][i]));
            }
    }

    cout << Ans << endl;
    return 0;
}
/*
10
2 3 12 4 212 4 2 1 3 33
*/

D

直接爆搜。
当两个点有直接相连的边时,假设他们在一个团里,那么显然和他们相连的点都要与两个点都直接相连,所以我们就去找到某个点,和两个点中一个相连一个不相连。枚举删边加边即可。

E

这不是原题吗。
二分一个答案,判定的时候贪心地条,判断需要移动的石头是否符合题意

CODE

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define R register int
const int N = 5e5 + 5;
inline int read() {
    int s = 0 , w = 1; char ch = getchar();
    while(ch < 48 || ch > 57) {if(ch == '-') w = -1; ch = getchar();}
    while(ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48)  ,ch = getchar();
    return s * w;
}

int n , m , ans , a[N];

inline bool judge(int mid) {
    R i , j = 0 , cnt = 0;
    for(i = 1 ; i <= n ; ++ i)
        if(a[i] - a[j] >= mid) j = i , ++ cnt;
    if(a[n + 1] - a[j] < mid) -- cnt;
    return cnt >= n - m;
}

int main() {
//  freopen("stone.in","r",stdin);
//  freopen("stone.out","w",stdout);
    R i ;
    int mid , l = 1 , r = read();
    n = read() , m = read();
    for(i = 1 ; i <= n ; ++ i) a[i] = read();
    a[n + 1] = r;
    while(l <= r) {
        mid = (l + r) >> 1;
        if(judge(mid)) ans = mid , l = mid + 1;
        else r = mid - 1;
    }
    cout << ans << endl;
    fclose(stdin); fclose(stdout);
    return 0;
}

F

显然树上经过一条边的路径数量是这条边两边的点数之积,计算经过每条边的路径数量然后排序从大到小染色即可。

#include <algorithm>
#include <cctype>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstring>
#include <deque>
#include <functional>
#include <list>
#include <map>
#include <iomanip>
#include <iostream>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
using namespace std;
#define int long long
#define I inline
#define ri register int
#define For(i , x , y) for(ri i = x ; i <= y ; ++ i)
#define Next(i , x) for(ri i = head[x] ; i ; i = e[i].nxt)
#define pb(x) push_back(x)
#define lowbit(x) x & -x
I int read() {
    int s = 0 , w = 1; char ch = getchar();
    while(ch < 48 || ch > 57) {if(ch == '-') w = -1; ch = getchar();}
    while(ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48) , ch = getchar();
    return s * w;
}

const int N = 1e6 + 5;
int n , head[N] , tot , f[N] , a[N];
struct Edge {
    int to , nxt;
} e[N << 1];

I void addedge(int x , int y) {
    e[++ tot] = (Edge) {y , head[x]} , head[x] = tot;
}

I void dfs(int u , int par) {
    f[u] = 1;
    Next(i , u) {
        int v = e[i].to;
        if(v == par) continue;
        dfs(v , u) ;
        f[u] += f[v];

    }

    if(f[u] && f[u] != n) a[++ tot] = f[u] * (n - f[u]);
}
signed main() {
    n = read();
    For(i , 1 , n - 1) {
        int u = read() , v = read();
        addedge(u , v) ; addedge(v , u);
    }
    tot = 0 ;
    dfs(1 , 1);
    sort(a + 1 , a + tot + 1 , greater <int> ());
    int Ans = 0;
    //For(i , 1 , tot) printf("%d \n" , a[i]);
    For(i , 1 , tot) Ans += a[i] * i;
    cout << Ans << endl;
    return 0;
}