概述
A. Red and Blue Beans
思路:不妨假设r<b ,当b-r足够小时,一定是输出YES的。
只有当b-r 足够大时,才会无解。 极端情况就是 对于每一个口袋(packet) ,只放1个red bean 和d+1个blue bean,因此当r*(d+1)<b时无解。
代码:(注意相乘会爆int)
#include <iostream>
#include <cmath>
#include <map>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 10010;
int a[N];
int main()
{
int T;cin>>T;
ll n;
ll r,b,d;
while(T--)
{
cin>>r>>b>>d;
ll mi = min(r,b),ma = max(r,b);
if(mi*(d+1)<ma) puts("NO");
else puts("YES");
}
return 0;
}
B. The Cake Is a Lie
观察知,无论怎么走,从(1,1) 到(n,m) 所需的花费相同。
代码:
#include <iostream>
#include <cmath>
#include <map>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 10010;
int a[N];
int main()
{
int T;cin>>T;
ll n,m,k;
ll d;
while(T--)
{
cin>>n>>m>>k;
d = n-1+(m-1)*n;
if(d==k)
puts("YES");
else puts("NO");
}
return 0;
}
C. Berland Regional
思路:其实暴力就可以解决,给每个队的人按照能力排序(降序),然后记录前缀和。 枚举k,找到每只队伍大小距离k的倍数最近的值(例如队伍大小是 d 使得d-=d%k 即可,这样就满足了d是k的倍数),累加即可。 但是这样的复杂度是O(n^2) 容易超时,注意到当队伍大小d<k时就退出,因此我们可以对队伍大小进行排序(用pair记录队伍人数和队伍号) ,对队伍人数降序排列。当d<k时直接break即可
#include <iostream>
#include <cmath>
#include <map>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 200010;
typedef pair<int,int> PII;
struct stu{
int u,s;
}a[N];
vector<ll> re[N];
PII op[N];
int cnt[N];
int cmp(int a,int b)
{
return a>b;
}
int main()
{
int T;cin>>T;
int n,m,k;
ll d;
while(T--)
{
ll res = 0;
scanf("%d",&n);
memset(cnt,0,sizeof cnt);
memset(op,0,sizeof op);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i].u);
re[i].clear();
cnt[a[i].u]++;
}
int now = 0;
for(int i=1;i<=n;i++)
if(cnt[i]) op[++now] = {cnt[i],i};
sort(op+1,op+1+now);
reverse(op+1,op+1+now);
for(int i=1;i<=n;i++)
scanf("%d",&a[i].s);
for(int i=1;i<=n;i++)
{
re[a[i].u].push_back(a[i].s);
}
for(int i=1;i<=n;i++)
sort(re[i].begin(),re[i].end(),cmp);
for(int i=1;i<=n;i++)
{
int t = re[i].size();
for(int j=1;j<t;j++)
re[i][j] = re[i][j-1]+re[i][j];
}
//cout<<"de:"<<sum[1][2]<<endl;
for(int k=1;k<=n;k++)
{
ll res = 0;
for(int s=1;s<=now;s++)
{
int i = op[s].second;
int t = re[i].size();
if(t<k) break;
t-=t%k;
res+=re[i][t-1];
}
printf("%lld ",res);
}
puts("");
}
return 0;
}
D. Maximum Sum of Products
裸裸的区间dp,假设f[l][r] 代表反转l~r之间的值所形成的值 则有f[l][r] = f[l+1][r-1] - a[l]*b[l] - a[r]*b[r] + a[l]*b[r] + a[r]*b[l]
代码
#include <iostream>
#include <cmath>
#include <map>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 5010;
ll a[N],b[N];
ll f[N][N];
int main()
{
int n;cin>>n;
ll res = 0;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
scanf("%d",&b[i]),res+=a[i]*b[i];
for(int i=1;i<=n;i++)
f[i][i] = f[i][i-1] = res;
int r;
for(int len = 2;len<=n;len++)
{
for(int l = 1;l+len-1<=n;l++)
{
r = l+len-1;
f[l][r] = f[l+1][r-1] - a[l]*b[l] - a[r]*b[r] + a[l]*b[r] + a[r]*b[l];
res = max(res,f[l][r]);
}
}
cout<<res;
return 0;
}
记忆化搜索写法
#include <iostream>
#include <cmath>
#include <map>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 5010;
ll a[N],b[N];
ll f[N][N];
ll d;
ll dp(int l,int r)
{
if(f[l][r]) return f[l][r];
return f[l][r] = dp(l+1,r-1) - a[l]*b[l] - a[r]*b[r] + a[l]*b[r] + a[r]*b[l];
}
int main()
{
int n;cin>>n;
ll res = 0;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
scanf("%d",&b[i]),res += a[i]*b[i];
for(int i=1;i<=n;i++)
f[i][i] = f[i][i-1] = res;
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
res = max(res,dp(i,j));
cout<<res;
return 0;
}
最后
以上就是愤怒冥王星为你收集整理的Educational Codeforces Round 108 (Rated for Div. 2) ABCD题解的全部内容,希望文章能够帮你解决Educational Codeforces Round 108 (Rated for Div. 2) ABCD题解所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复