【题目】题目可以在这里看:http://codeforces.com/gym/101102/problem/A

【A】Coins

【题意】在A,B两个大集合里面选子集使得他们的和为W,并且两个子集的和的差<=K。

【解题方法】背包问题计算方案数,注意要考虑空集。

【代码君】

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N =15000;
const int mod=1e9+7;
int a[200],b[200];
LL dp1[200][16000],dp2[200][16000];
int main()
{
    int T,n,m,k,w;
    scanf("%d",&T);
    while(T--){
        memset(dp1,0,sizeof(dp1));
        memset(dp2,0,sizeof(dp2));
        scanf("%d%d%d%d",&n,&m,&k,&w);
        for(int i=0;i<n;i++){
            scanf("%d",&a[i]);
        }
        for(int i=0;i<m;i++){
            scanf("%d",&b[i]);
        }
        dp1[0][a[0]]=1;
        dp1[0][0]=1;
        for(int i=1;i<n;i++){
            for(int j=0;j<=N;j++){
                dp1[i][j]+=dp1[i-1][j];
                if(j-a[i]>=0) dp1[i][j]=(dp1[i][j]+dp1[i-1][j-a[i]])%mod;
            }
        }
        dp2[0][b[0]]=1;
        dp2[0][0]=1;
        for(int i=1;i<m;i++){
            for(int j=0;j<=N;j++){
                dp2[i][j]+=dp2[i-1][j];
                if(j-b[i]>=0) dp2[i][j]=(dp2[i][j]+dp2[i-1][j-b[i]])%mod;
            }
        }
        LL ans=0;
        for(int i=0;i<=w;i++){
            if(abs(w-i-i)<=k) ans=(ans+dp1[n-1][i]*dp2[m-1][w-i])%mod;
        }
        printf("%I64d\n",ans);
    }
    return 0;
}

【B】

【题意】用已经有的火柴去拼成更大的数字,问这个最大数字。

【解题方法】只需要考虑拼火柴的上下界,然后贪心即可。

【AC 代码】

//
//Created by just_sort 2016/9/30 19:27
//Copyright (c) 2016 just_sort.All Rights Reserved
//

#include <set>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int f[10]={6,2,5,5,4,5,6,3,7,6};
char s[100010];
int main()
{
    int T,n;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%s",&n,s);
        int sum = 0;
        for(int i = 0; i < n; i++){
            sum += f[s[i]-'0'];
        }
        for(int i = 1; i < n; i++){
            for(int j = 9; j >= 0; j--){
                int temp = sum - f[j];
                if(temp <= (n-i)*7 && temp >= (n-i)*2){
                    printf("%d",j);
                    sum -= f[j];
                    break;
                }
            }
        }
        for(int i = 9; i >= 0; i--){
            if(sum == f[i]){
                printf("%d",i);
                break;
            }
        }
        printf("\n");
    }
    return 0;
}

【C】

【题意】给了一些人比赛的得分,问从哪个位置开始,这个比赛的冠军就确定了。

【解题方法】我们可以考虑记录最大值的位置,然后倒着扫描一遍,那么第一个不等于最后一次操作确定的最大值,就是这个位置了。

【代码君】

//
//Created by just_sort 2016/9/30 15:32
//Copyright (c) 2016 just_sort.All Rights Reserved
//

#include <set>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1e6+10;
struct node{
    int l,r;
    int maxv,id;
}Tree[maxn*4];
int ans[maxn];
void pushup(int rt){
    Tree[rt].maxv = max(Tree[rt*2].maxv,Tree[rt*2+1].maxv);
    if(Tree[rt*2].maxv >= Tree[rt*2+1].maxv){
        Tree[rt].id = Tree[rt*2].id;
    }
    else{
        Tree[rt].id = Tree[rt*2+1].id;
    }
}
void Build(int l,int r,int rt)
{
    Tree[rt].l = l,Tree[rt].r = r;
    if(l == r){
        Tree[rt].maxv = 0;
        Tree[rt].id = l;
        return ;
    }
    int mid = (l + r)/2;
    Build(l,mid,rt*2);
    Build(mid+1,r,rt*2+1);
    pushup(rt);
}
void update(int pos,int v,int rt){
    if(Tree[rt].l == Tree[rt].r){
        Tree[rt].maxv += v;
        return ;
    }
    int mid = (Tree[rt].l + Tree[rt].r)/2;
    if(pos <= mid) update(pos,v,rt*2);
    else update(pos,v,rt*2+1);
    pushup(rt);
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n,q;
        //memset(ans,0,sizeof(ans));
        scanf("%d%d",&n,&q);
        Build(1,n,1);
        for(int i = 1; i <= q; i++){
            int id,val;
            scanf("%d%d",&id,&val);
            update(id,val,1);
            ans[i] = Tree[1].id;
        }
        int pos;
        for(int i = q; i > 0; i--){
            if(ans[i] != ans[q]){
                break;
            }
            pos = i;
        }
        if(pos == 1 && ans[pos] == 1){
            printf("0\n");
        }
        else{
            printf("%d\n",pos);
        }
    }
    return 0;
}

【D】

【题意】问一个大的矩阵里面有多少个子矩阵,满足每个子矩阵的每一个元素想等。

【解题方法】特别感谢 qwb 大牛替我解答这一个问题。单调栈的经典题目了,不会单调栈可以去学一下。直接放代码了。

【代码君】

//
//Created by just_sort 2016/9/30 15:32
//Copyright (c) 2016 just_sort.All Rights Reserved
//

#include <set>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1002;
int S[maxn][maxn],TOP[maxn][maxn];
int A[maxn],B[maxn],sz,sum;
int n,m;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m; j++){
                scanf("%d",&S[i][j]);
            }
        }
        long long ans = 0;
        for(int i = 1; i <= n; i++){
            sz = sum = 0;
            for(int j = 1; j <= m; j++){
                int h = (S[i][j] == S[i-1][j] ? TOP[i-1][j] + 1 : 1);
                int w = 1;
                TOP[i][j] = h;
                if(S[i][j] != S[i][j-1]) sum = sz = 0;
                while(sz && h <= A[sz]){
                    sum -= A[sz] * B[sz];
                    w += B[sz--];
                }
                A[++sz] = h;B[sz] = w;
                sum += A[sz] * B[sz];
                ans += sum;
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

【E】水题,输出(n+4)/5即可。

【F】

【题意】问经过最多一次替换,原串可以得到的字典序最小的串是什么?

【解题方法】简单贪心即可。

【AC 代码】

#include<bits/stdc++.h>
using namespace std;
char s[200000];
int flag[26],f[26];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        memset(flag,0,sizeof(flag));
        memset(f,0,sizeof(f));
        scanf("%s",s);
        for(int i=0;s[i];i++){
            flag[s[i]-'a']=1;
        }
        int ans1=-1,ans2=-1,ff=0;
        for(int i=0;s[i];i++){
            f[s[i]-'a']=1;
            for(int j=0;j<s[i]-'a';j++){
                if(flag[j]&&f[j]==0){
                    ans1=s[i]-'a';
                    ans2=j;
                    ff=1;
                    break;
                }
            }
            if(ff==1) break;
        }
        if(ans1!=-1){
            for(int i=0;s[i];i++){
                if(s[i]-'a'==ans1){
                    s[i]='a'+ans2;
                }
                else if(s[i]-'a'==ans2){
                    s[i]='a'+ans1;
                }
            }
        }
        printf("%s\n",s);
    }
    return 0;
}

【H】水题,判断相邻空位是否>=(m+1)即可。

【I】

【题意】给了一个矩形,大小R*C,然后给了一个机器人的一串指令,现在机器人的初始位置不定,如果机器人执行当前指令,它会走出r*c的区域的话,那么当前指令会被跳过,问最少有多少条指令会被跳过。

【解题方法】一种好的方法是,我们分别来统计横着走和上下走的对答案的贡献。所以我们分别拿出横的和竖的走法,分别统计就行了。

【代码君】

//
//Created by just_sort 2016/9/30 20:23
//Copyright (c) 2016 just_sort.All Rights Reserved
//

#include <set>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 2e5+10;
char str[maxn];
int X[maxn],Y[maxn],cntx,cnty;
int ans,maxx,minn,pos,sum;
bool flag;

int main()
{
    int T,r,c;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%s",&r,&c,str);
        int len = strlen(str);
        cntx = 0;
        cnty = 0;
        memset(X,0,sizeof(X));
        memset(Y,0,sizeof(Y));
        for(int i = 0; i < len; i++){
            if(str[i] == '>') X[cntx++] = 1;
            else if(str[i] == '<') X[cntx++] = -1;
            else if(str[i] == '^') Y[cnty++] = -1;
            else if(str[i] == 'v') Y[cnty++] = 1;
        }
        sum = 0;
        flag = 0;
        ans = minn = maxx = pos = 0;
        for(int i = 0; i <cntx; i++){
            pos += X[i];
            if(flag){
                if(pos >= c){
                    ans++;
                    pos = c - 1;
                }
                else if(pos < 0){
                    ans++;
                    pos = 0;
                }
            }
            else{
                minn = min(minn,pos);
                maxx = max(maxx,pos);
                if(maxx - minn >= c){
                    flag = 1;
                    ans++;
                    if(pos == minn){
                        pos = 0;
                    }
                    else{
                        pos = c - 1;
                    }
                }
            }
        }
        sum += ans;
        flag = 0;
        ans = minn = maxx = pos = 0;
        for(int i = 0; i <cnty; i++){
            pos += Y[i];
            if(flag){
                if(pos >= r){
                    ans++;
                    pos = r - 1;
                }
                else if(pos < 0){
                    ans++;
                    pos = 0;
                }
            }
            else{
                minn = min(minn,pos);
                maxx = max(maxx,pos);
                if(maxx - minn >= r){
                    flag = 1;
                    ans++;
                    if(pos == minn){
                        pos = 0;
                    }
                    else{
                        pos = r - 1;
                    }
                }
            }
        }
        sum += ans;
        printf("%d\n",sum);
    }
    return 0;
}