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; }