B:「金」点石成金
题面:
图片说明
图片说明
思路:注意到n范围很小直接暴力。
dfs暴力枚举每个物品选和不选产生的影响,注意当魔法为负数时修改成0,财富为负数修改为0即可。
代码:

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

const int maxn = 2e5 + 10;
typedef long long int ll;
struct node{
    ll a,b,c,d;
    node(){}
    node(ll a,ll b,ll c,ll d):a(a),b(b),c(c),d(d){}
}a[maxn];
ll ans = 0;
int n;
void dfs(int dep,ll hp,ll s){
    if(dep >= n){
        ans = max(ans,s * hp);
        return ;
    }
    dfs(dep + 1,hp - a[dep + 1].b < 0 ? 0 :hp - a[dep + 1].b,s + a[dep + 1].a);
    dfs(dep + 1,hp + a[dep + 1].c,s - a[dep + 1].d < 0 ? 0 :s - a[dep + 1].d);
}
void solved(){
    cin>>n;
    for(int i = 1; i <= n; i++){
        ll x,y,z,q;cin>>x>>y>>z>>q;
        a[i] = {x,y,z,q};
    }
    dfs(1,a[1].c,0);
    dfs(1,0,a[1].a);
    cout<<ans<<endl;
}
int main(){
    solved();
    return 0;
}

E:Board
题面:
图片说明
思路:模拟即可。 把每行的值 - 这行最小值(对于任意ai > 0),把每列的值 - 这列最小值(对于任意aj > 0),再用一个变量统计减去了多少就是那么未知数的值。减完之后最后矩阵应该是全0.
代码:

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

const int maxn = 1e4 + 10;
typedef long long int ll;
int a[maxn][maxn];
void solved(){
    int n;cin>>n;
    int ans = 0;
    for(int i = 1; i <= n; i++){
        int mm = 1e6 + 10;

        bool flag = true;
        for(int j = 1; j <= n; j++){
            cin>>a[i][j];
            if(a[i][j] != -1)
            mm = min(a[i][j],mm);

            if(a[i][j] == 0)flag = false;
        }
        if(!flag)continue;
        for(int j = 1; j <= n; j++){
            if(a[i][j] != -1)
            a[i][j] -= mm;
            else ans += mm;
        }
    }

    for(int i = 1; i <= n; i++){
        int mm = 1e6 + 10;

        bool flag = true;
        for(int j = 1; j <= n; j++){
            if(a[j][i] != -1)
            mm = min(mm,a[j][i]);
            if(a[j][i] == 0)flag = false;
        }
        if(!flag)continue;

        for(int j = 1; j <= n; j++){
            if(a[j][i] != -1)
            a[j][i] -= mm;
            else ans += mm;
        }
    }

//    cout<<endl;
//    for(int i = 1; i <= n; i++){
//        for(int j = 1; j <= n; j++){
//            cout<<a[i][j]<<"  ";
//        }
//        cout<<endl;
//    }
    cout<<ans<<endl;
}
int main(){
    solved();
    return 0;
}

A:小A买彩票
题面:
图片说明
思路:
一开始看到n非常小直接写了暴力t了,不妨看一下暴力的写法。
代码:

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

const int maxn = 2e5 + 10;
typedef long long int ll;

ll ans;
int n;
void dfs(int dep,int s){
    if(dep >= n){
        if(s >= 3 * n)ans++;
        return ;
    }
    for(int i = 1; i <= 4; i++){
        dfs(dep + 1,s + i);
    }
}
void solved(){
    cin>>n;
    dfs(1,1);
    dfs(1,2);
    dfs(1,3);
    dfs(1,4);
    if(n == 0){
        cout<<"1/1"<<endl;
    }else{
        ll res = pow(4,n);
        ll _gcd = __gcd(res,ans);
        cout<<ans / _gcd <<"/"<<res / _gcd<<endl;
    }
}
int main(){
    solved();
    return 0;
}

这个暴力很多部分有重复计算,导致效率过低,所以我们考虑用数组记忆化搜索。注意到对于任意的n,只有[3n,4n]这段满足题面要求,所以我们就枚举这段的数量,用dp数组来记忆之前的结果。就可以避免大量重复计算。
代码:

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

typedef long long int ll;
ll dp[50][550];
//dp[i][j]:第i次抽奖金额为j的数量
ll n;
ll dfs(ll dep,ll s){
    //cout<<dep <<"  "<<s<<endl;
    if(dep > n){
        if(s == 0)return 1;
        return 0;
    }
    ll ans = 0;
    if(dp[dep][s] != -1)return dp[dep][s];

    for(int i = 1; i <= 4; i++){

        ans += dfs(dep + 1,s - i);
    }
    //cout<<ans<<endl;
    dp[dep][s] = ans;
    return ans;
}
void solved(){
    cin>>n;
    memset(dp,-1,sizeof(dp));
    if(n == 0){
        cout<<"1/1"<<endl;
    }else{
        ll ans = 0;
        for(ll i = n * 3; i <= n * 4; i++){
            ans += dfs(1,(ll)i);
        }
        ll res = pow(4,n);
        ll _gcd = __gcd(res,ans);
        cout<<ans / _gcd <<"/"<<res / _gcd<<endl;
    }
}
int main(){
    solved();
    return 0;
}