A:Course
B:Sample Game
C:LCS
题意:已知三个字符串长度,和他们两两之间的LCS长度a,b,c,输出满足条件的三个字符串。
思路:构造题。min({a,b,c})肯定是他们两两之间共有的一个前缀,所以给三个字符串加上这么多个'a'后,然后以此根据a,b,c剩下的值去填'b'和'c',全填完后如果有一个字符串的长度大于n,则输出-1。否则继续填字符d或者e或f直至字符串长度等于n。
代码:

#include <bits/stdc++.h>
using namespace std;

int main()
{
    int a,b,c,n; cin >> a >> b >> c >> n;
    string s1,s2,s3;
    int minn=min(a,min(b,c));
    a-=minn,b-=minn,c-=minn;
    for(int i=1;i<=minn;i++) {
        s1+='a';
        s2+='a';
        s3+='a';
    }
    if(a>=b&&a>=c) {
        for(int i=1;i<=a;i++) {
            s2+='b';
            s1+='b';
        }
        if(b==0) 
           for(int i=1;i<=c;i++) {
                 s1+='c';
               s3+='c';
        }
        else if(c==0) {
            for(int i=1;i<=b;i++) {
    s3+='c';s2+='c';
            }
        }
    }
    else if(b>=a&&b>=c) {
        for(int i=1;i<=b;i++) {
            s2+='b';
            s3+='b';
        }
        if(a==0) 
           for(int i=1;i<=c;i++) {
                 s1+='c';
               s3+='c';
        }
        else if(c==0) {
            for(int i=1;i<=a;i++) {
    s1+='c';s2+='c';
            }
        }
    }
    else if(c>=a&&c>=b) {
        for(int i=1;i<=c;i++) {
            s3+='b';
            s1+='b';
        }
        if(b==0) 
           for(int i=1;i<=a;i++) {
                 s1+='c';
               s2+='c';
        }
        else if(a==0) {
            for(int i=1;i<=b;i++) {
    s3+='c';s2+='c';
            }
        }
    }
    int len1=s1.length(),len2=s2.length(),len3=s3.length();
    if(len1>n||len2>n||len3>n) {
        cout << "NO" << endl;
        return 0;
    }
    if(len1<n) {
        for(int i=1;i<=n-len1;i++) s1+='d';
    }
    if(len2<n) {
        for(int i=1;i<=n-len2;i++) s2+='e';
    }
    if(len3<n) {
        for(int i=1;i<=n-len3;i++) s3+='f';
    }
    cout << s1 << endl << s2 << endl << s3 << endl;
    return 0;
 } 

D:Rebuild Tree
E:Tree Xor
F:Just a joke
题意:有n个点的无向图,两个人每次可以选择进行一种操作;1.删掉一条边;2.删掉一个没有环的连通分量。 问最后谁赢。
思路:第一种操作边数-1,第二种操作点数-k且边数-(k-1)。所以每次不管进行那种操作边和点的个数都会减少一个奇数,所以判断一下n+m的奇偶性即可。
代码:

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int n,m; cin >> n >> m;
    for(int i=1;i<=n;i++) {
        int u,v; cin >> u >> v;
    }
    if((m+n)%2==0) {
        cout << "Bob" << endl;
    }
    else cout << "Alice" << endl;
    return 0;
}

G:Product
H:Convolution
I:Inverse Pair
题意:给你一个序列a,现在你可以对a序列每个数+1或+0使它变成一个新序列b,序列ci=bi+ai。输出序列c的逆序对数。
思路:首先求出序列a中的逆序对数,然后记录下每个ai加1是否之前已经出现过了,统计这样的ai的个数。因为如果存在,我们令它加1,就减少了一个逆序对的数量。最后二者做差即可。
代码:

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll N = 2e5 + 5;
ll b[N];
struct node{
    ll val;
    ll pos;
}a[N];

ll tree[N], c[N];
ll sum, n;

int cmp(node a, node b) {
    return a.val < b.val;
}

void add(int m, int k) {
    while (m <= n) {
        tree[m] += k;
        m += m & -m;
    }
}

ll inquiry(ll n) {
    ll sum = 0;
    while (n) {
        sum += tree[n];
        n -= n & -n;
    }
    return sum;
}

int main() {
    cin >> n;
    sum = 0;
    memset(tree, 0, sizeof(tree));
    for (int i = 1; i <= n; i++) {
        cin >> a[i].val;
        a[i].pos = i;
    }
        ll tmp=0;
    for(int i=1;i<=n;i++) {
        if(b[a[i].val+1]) tmp++;
        else b[a[i].val]=1;
    }
    for (int i = 1; i <= n; i++) {
    }
    sort(a + 1, a + 1 + n, cmp);
    ll cnt = 1;
    for (int i = 1; i <= n; i++) {
        if (i != 1 && a[i].val != a[i - 1].val)    cnt++;
        c[a[i].pos] = cnt;
    }
    for (int i = 1; i <= n; i++) {
        add(c[i], 1);
        sum += (i - inquiry(c[i]));
    }
    cout << sum - tmp << endl;
}

J:Average
题意:给你两个序列a和b,矩阵,让你在矩阵w中找一个子矩阵,其中子矩阵的长不得小于x,宽不得小于y且子矩阵的平均值最大。输出该平均值
思路:由题意我们可以写出平均值的式子图片说明,又因为w[i][j]=a[i]+b[j],所以子矩阵的和为:图片说明 ,联立上面两个式子可得平均值最简式为:图片说明
所以这道题就变成了去求a的长度至少为x的子区间的最大平均值和b的长度至少为y的最大平均值相加即可,poj2018裸题,二分平均数为mid,把原数组中每个数都减去mid,若最大和>0,就是平均数取小了。这就涉及到均值比较的技巧:平均值大小的比较,可以转换为每对对应元素差值之和与0的比较。。
代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
double a[100005],b[100005],sum[100005];
double aa[100005],bb[100005],ssum[100005];
int main(){
    int n,m,x,y;
    cin>>n >> m>>x>>y;
    for(int i=0;i<n;i++) scanf("%lf",&a[i]);
    for(int i=0;i<m;i++) scanf("%lf",&aa[i]);
    double eps=1e-6;
    double l1=-1e6,r1=1e6;
    while(r1-l1>eps){
        double mid=(r1+l1)/2;
        for(int i=0;i<n;i++) b[i]=a[i]-mid;
        for(int i=0;i<n;i++) sum[i]=sum[i-1]+b[i];
        double ans=-1e10,minval=1e10;
        for(int i=x-1;i<n;i++){
            minval=min(minval,sum[i-x]);
            ans=max(ans,sum[i]-minval);
        }
        if(ans>0) l1=mid; else r1=mid;
    }
    double l2=-1e6,r2=1e6;
    while(r2-l2>eps){
        double mid=(r2+l2)/2;
        for(int i=0;i<m;i++) bb[i]=aa[i]-mid;
        for(int i=0;i<m;i++) ssum[i]=ssum[i-1]+bb[i];
        double ans=-1e10,minval=1e10;
        for(int i=y-1;i<m;i++){
            minval=min(minval,ssum[i-y]);
            ans=max(ans,ssum[i]-minval);
        }
        if(ans>0) l2=mid; else r2=mid;
    }
    printf("%.10lf\n",r1+r2);
    return 0;
}