题解(隔板法,插空法,最大生成树)2023.6.11

E - AtCoder Express 2
思路:转化为二维前缀和,查询时查(y,y)和(x,x)之间的范围
 

#include
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(fast) 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ms(x,y) memset(x,y,sizeof x);
#define YES cout<<"YES"<<'\n';
#define NO  cout<<"NO"<<'\n';
#define endl cout<<'\n';
typedef long long ll;
const ll maxn=510,inf = 1e18 ; 
const ll mod = 1e9 + 7;
using namespace std;
int a[maxn][maxn];
void solve() {
    int n, m, q;
    cin >> n >> m >> q;
    for (int i = 1; i <= m; i++) {
        int x, y;
        cin >> x >> y;
        a[x][y]++;
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            a[i][j] +=  a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1];
        }
    }
     while (q--) {   //查询的时候
         int x, y;
         cin >> x >> y;
         cout << a[y][y] - a[x - 1][y] - a[y][x - 1] + a[x - 1][x - 1] << '\n';
     }
 }
signed main()
{
    ios::sync_with_stdio(false);
    int t=1;
    //cin >> t;
    while (t--) {
        solve();
    }
}

1640 天气晴朗的魔法
思路:先kruskal算法求最小生成树中的最大边的最小值,再求最大生成树,使用快读,cin时间超限
 

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ms(x,y) memset(x,y,sizeof x);
#define YES cout<<"YES"<<'\n';
#define NO  cout<<"NO"<<'\n';
#define endl cout<<'\n';
typedef long long ll;
const ll maxn=2e5+10,inf = 1e18 ; 
const ll mod = 1e9 + 7;
using namespace std;
using namespace std;
typedef long long ll;
int f[maxn];
ll Max_Edge;
inline int read()
{
    int f = 1;
    int x = 0;
    char c = getchar();
    while (c < '0' || c>'9') {
        if (c == '-') {
            f = -f;
        }
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        x = (x << 1) + (x << 3) + (c ^ 48);
        c = getchar();
    }
    return x * f;
}
struct edge {
    int u, v;
    ll w;
}a[maxn];
bool cmp1(edge A, edge B) {
    return A.w < B.w;
}
bool cmp2(edge A, edge B) {
    return A.w > B.w;
}
int find(int x) {
    if (f[x] == -1) return x;
    return f[x] = find(f[x]);
}
int n, m;
int kruskal1() {
    // 返回最小生成树的最后一条边的下标 ans
    // Edge[ans].v 为最小生成树中的最大边
    memset(f, -1, sizeof(f)); 
 
    int num = 0, ans = 1;
    for (int i = 1; i <= m; i++) {
       int s= find(a[i].u);
        int e = find(a[i].v);
        if (s != e) {
            num++;
            ans = i;
            f[min(s,e)] = max(s,e);
        }
        if (num >= n - 1) {
            break;
        }
    }
    if (num >= n - 1) {
        return ans;
    }
    else {
        return -1;
    }
}
ll kruskal2() {
    // 在所有小于等于 Max_Edge 的边中求得最大生成树
    memset(f, -1, sizeof(f));
    ll ans = 0, num = 0;
    for (int i = 1; i <= m; i++) {
        if (a[i].w > Max_Edge)
            continue;
        int s = find(a[i].u);
        int e = find(a[i].v);
        if (s != e) {
            num++;
            ans += a[i].w;
            f[min(s, e)] = max(s, e);
        }
        if (num >= n - 1)
            break;
    }
    if (num >= n - 1)
        return ans;
    return -1;
}
int main() {
    cin >> n >> m;
    int u, v, w;
    for (int i = 1; i <= m; i++) {
        u = read();
        v = read();
        w = read();
        a[i].u = u, a[i].v = v;
        a[i].w = w;
    }
    sort(a + 1, a + m + 1, cmp1); // 升序,最小生成树
    int index = kruskal1();
    Max_Edge = a[index].w;
    sort(a + 1, a + m + 1, cmp2); // 降序,最大生成树
    cout << kruskal2();
    return 0;
}

3D模型
思路:首先计算一个柱面的表面积,之后减去重合的面积
 

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ms(x,y) memset(x,y,sizeof x);
#define YES cout<<"YES"<<'\n';
#define NO  cout<<"NO"<<'\n';
#define endl cout<<'\n';
typedef long long ll;
const ll maxn=1e3+10,inf = 1e18 ; 
const ll mod = 1e9 + 7;
using namespace std;
int a[maxn][maxn], ans;
void solve() {
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            scanf("%1d", &a[i][j]);
            if (a[i][j] == 0) continue;
            ans += a[i][j] * 4 + 2;
                ans -= min(a[i - 1][j], a[i][j]) * 2;
                ans -= min(a[i][j - 1], a[i][j]) * 2;
        }
    }
    cout << ans << '\n';
}
int main() {
    solve();
    return 0;
}

J - Blue and Red Balls
题意:k个蓝球,n-k个红球,把k个蓝球分成m堆,放进红球中,有多少种方案
思路:m堆放进红球,(插空法)有C(n-k+1,m)方案数,分成m堆(,隔板法)有C(k-1,m-1)
 

#include
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(fast) 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ms(x,y) memset(x,y,sizeof x);
#define YES cout<<"YES"<<'\n';
#define NO  cout<<"NO"<<'\n';
#define endl cout<<'\n';
typedef long long ll;
const ll maxn=2e5+10,inf = 1e18 ; 
const ll mod = 1e9 + 7;
using namespace std;
int a[maxn];
ll inv(ll a,ll m) {   //线性地推,不进行储存 
    if (a == 1)return 1;
    return inv(m % a, m) * (m - m / a) % m;
}
ll C(int a, int b) { //组合计算的快速方法1,b>=a
    ll t1 = 1, t2 = 1;
    for (int i = b; i >= (b - a + 1); i--)t1 = t1 * i % mod;
    for (int i = a; i >= 1; i--)t2 = t2 * i % mod;
    return t1 * inv(t2, mod) % mod;
}
 void solve(){
     int n, k;
     cin >> n >> k;
     for (int i = 1; i <= k; i++) { //枚举堆数
         cout << (C(i, n - k +1)%mod * C(i - 1, k - 1) % mod)%mod << '\n';
     }
 }
signed main()
{
    ios::sync_with_stdio(false);
    int t=1;
    //cin >> t;
    while (t--) {
        solve();
    }
}

你可能感兴趣的:(c++,算法)