感觉没什么意思,这场月赛出题人有点问题。
B
题意:给定一定的数据填充顺序和每一个填充层的名称,只有填充满了上一层才可以填充下一层。
但是每一层又属于某一个大层,一个大层中包含了若干不同的小层。输出时请按照先大层后小层的顺序来输出,小层请按照小层的顺序来输出。
大层顺序:按照数字1 2 3 4 5 6 7
小层顺序:按照字母spdf顺序来输出
思路:暴力,先把填充顺序打个表,然后再把输出顺序打个表,然后用map存一下每一层的填充数,然后按照输出顺序去遍历即可。
#include<bits/stdc++.h>
#define int long long
using namespace std;
int con[20]={0,2,2,6,2,6,2,10,6,2,10,6,2,14,10,6,2,14,10,6};
string pos[20]={"0","1s","2s","2p","3s","3p","4s","3d","4p","5s","4d","5p","6s","4f","5d","6p","7s","5f","6d","7p"};
string ans[20]={"0","1s","2s","2p","3s","3p","3d","4s","4p","4d","4f","5s","5p","5d","5f","6s","6p","6d","7s","7p"};
map<string,int>mp;
signed main()
{
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int t;
for(cin>>t;t;t--)
{
mp.clear();
int n;
cin>>n;
int cnt=1;
while(n)
{
if(n>con[cnt])
{
n-=con[cnt];
mp[pos[cnt]]=con[cnt];
cnt++;
}
else if(n<=con[cnt])
{
mp[pos[cnt]]=n;
cnt++;
n=0;
}
}
for(int i=1;i<20;i++)
if(mp[ans[i]])
cout<<ans[i]<<mp[ans[i]]<<" ";
cout<<endl;
}
return 0;
}
C:
题意:有n个数,每个数的范围是【1,m】,要求尽量从中选出n-2个数使其总和可以被m整除,如果这n-2个数的总和为sum,剩下两个数的总和为res
定义这n个数的价值如下
1.如果sum无法被m整除,那么其价值为0
2.如果sum可以被m整除,并且res也可以被m整除,价值为m
3.如果sum可以被整除,但res不能,那么价值为res%m
题目保证价值的唯一性。
思路:经典的举一推一做法。
我们遍历整个数组,假设当前的数就是我们要找的剩下的两张牌中的一张,那么为了让sum可以被m整除另一张势必是剩下的n-1张牌的总和取模于m的余数。如果不存在这样的两张牌,说明无法找出一个sum让其取模于m为0。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5+100;
int a[N];
map<int,int>mp;
signed main()
{
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int t;
for(cin>>t;t;t--)
{
mp.clear();
int n,m,sum=0;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum+=a[i];
mp[a[i]]++;
}
int ans=0;
for(int i=1;i<=n;i++)
{
int temp=sum-a[i];//枚举抽走一张牌
mp[a[i]]--;//防止重复抽一张牌
int res=temp%m;//剩下的牌,想要再收走一张然后满足取模m等于0,就需要抽走temp%m的价值
if(res==0)//说明得抽走一张价值为m的牌
res=m;
if(mp[res])//如果存在这样的牌
{
res+=a[i];//两张牌的和
if(res%m==0)
ans=m;
else
ans=res%m;
break;
}
mp[a[i]]++;//放回去
}
cout<<ans<<'\n';
}
return 0;
}
D
题意:
给定n个题目,有难度系数a和分数b,P值,W值
某人有初始压力值p,并且没做完一个题就可以让压力在[0,k]的范围内减小P或者增加W
如果当前压力值p小于b那么就可以做出这个题,并且获得点数a*p
如果当前压力值大于b那么就无法获得点数。
求,如果初始压力值你可以在[0,k]中随便选,n个题目你能获得的最大点数是多少。
特别的,此题空间限制位64MB
思路
设dp[i][j]为前i个物品在压力值为k的情况下的最大获得点数
然后发现第i个物品的答案只和i-1个物品的答案相关,所以只需要第一维的空间为2即可。
状态为dp[now][j]=max(dp[bef][j]+val[now],dp[bef][j-q[i-1]]+val[now],dp[bef][j+w[i-1]]+val[now]);
具体实现见代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5+100;
int n,m,k;
int a[N],b[N],q[N],w[N];
inline int gval(int x,int i){
return x>b[i]?0:x*a[i];
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n>>k;
for(int i=1;i<=n;i++)
cin>>a[i]>>b[i]>>q[i]>>w[i];
vector<int> dp(k+1,0);
for(int i=1;i<=n;i++)
{
vector<int> bef=dp;
for(int j=0;j<=k;j++)
{
if(i>1)
{
dp[j]=max(dp[j],bef[j]+gval(j,i));
if(j-q[i-1]>=0)
dp[j]=max(dp[j],bef[j-q[i-1]]+gval(j,i));
if(j+w[i-1]<=k)
dp[j]=max(dp[j],bef[j+w[i-1]]+gval(j,i));
}
else
dp[j]=gval(j,i);
}
}
int ans=0;
for(int i=0;i<=k;i++)
ans=max(ans,dp[i]);
cout<<ans<<'\n';
return 0;
}