A:Rudolf and the Ticket
题面:
分析:
暴力枚举
时间复杂度O(n^2),当然可以排序二分优化到O(nlog n)
代码:
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
typedef long long ll;
const int N=1e2+10,M=1e9+7;
int n,m,k;
int b[N],c[N];
void solve()
{
cin>>n>>m>>k;
for(int i=1;i<=n;i++){
cin>>b[i];
}
for(int i=1;i<=m;i++){
cin>>c[i];
}
int ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(b[i]+c[j]<=k){
ans++;
}
}
}
cout<<ans<<'\n';
}
int main()
{
std::ios::sync_with_stdio(0);
std::cin.tie(0);
int T=1;
cin>>T;
while(T--)
{
solve();
}
return 0;
}
B:Rudolf and 121
题面:
分析:
贪心
可以发现,最左侧和最右侧的非零元素只能分别通过操作右侧和左侧元素将其变为0
所以可以从两侧开始模拟操作,如果最后能将数组变成全0则YES,否则NO
当然,也可以单纯地从左往右或从右往左模拟
被操作的位置会变成下一个边界
代码:
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
typedef long long ll;
const int N=2e5+10,M=1e9+7;
int n;
int a[N];
void solve()
{
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
int l=2,r=n-1;
while(l<=r)
{
if(a[l-1]>0){//注意不要操作小于0的数,等于0无需操作
a[l]-=2*a[l-1];
a[l+1]-=a[l-1];
a[l-1]=0;
}
if(a[r+1]>0){
a[r]-=2*a[r+1];
a[r-1]-=a[r+1];
a[r+1]=0;
}
l++;
r--;
}
int flag=1;
for(int i=1;i<=n;i++){
if(a[i]!=0){
flag=0;
break;
}
}
if(flag){
cout<<"YES"<<'\n';
}else{
cout<<"NO"<<'\n';
}
}
int main()
{
std::ios::sync_with_stdio(0);
std::cin.tie(0);
int T=1;
cin>>T;
while(T--)
{
solve();
}
return 0;
}
C:Rudolf and the Ugly String
题面:
分析:
字符串匹配,贪心
对于单独的map或者pie,只要删除其中任意一个字符即可
注意到map和pie尾部和首部分别都有一个p,那么对于mapie只要删除p即可,操作一次
模拟匹配删除操作
代码:
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
typedef long long ll;
typedef pair<ll,ll> pll;
const int N=1e6+10,M=1e9+7;
int n;
string s,t1,t2;
void solve()
{
cin>>n>>s;
int l=0,ans=0;
while(l<=n-3)
{
int flag=0;
if(s[l]=='m'&&s[l+1]=='a'&&s[l+2]=='p'){
ans++;
l+=2;
flag=1;
}
if(s[l]=='p'&&s[l+1]=='i'&&s[l+2]=='e'){
if(flag==0){
ans++;
}
l+=2;
}
l++;
}
cout<<ans<<'\n';
}
int main()
{
std::ios::sync_with_stdio(0);
std::cin.tie(0);
int T=1;
cin>>T;
while(T--)
{
solve();
}
return 0;
}
D:Rudolf and the Ball Game
题面:
分析:
动态规划
有一道与这题近乎一样的题:
D-我不是大富翁_牛客小白月赛88 (nowcoder.com)
题解:
在以上做法的基础上修改:
因为初始位置不固定,边界条件修改成dp[0][x-1]=1
状态转移过程由c[i]来决定
输出答案时遍历dp[m][j]存储输出
代码(1):
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
typedef long long ll;
const int N=1e3+10,M=998244353;
int n,m,x;
int r[N];
char c[N];
int dp[N][N];
void solve()
{
cin>>n>>m>>x;
for(int i=1;i<=m;i++){
cin>>r[i]>>c[i];
}
for(int i=0;i<=m;i++){
for(int j=0;j<=n;j++){
dp[i][j]=0;
}
}
dp[0][x-1]=1;
for(int i=1;i<=m;i++){
for(int j=0;j<=n-1;j++){
int last1=((j-r[i])%n+n)%n,last2=(j+r[i])%n;
if(c[i]=='0'){
dp[i][j]=max(dp[i][j],dp[i-1][last1]);
}else if(c[i]=='1'){
dp[i][j]=max(dp[i][j],dp[i-1][last2]);
}else{
dp[i][j]=max(dp[i][j],max(dp[i-1][last1],dp[i-1][last2]));
}
}
}
vector<int> v;
for(int i=0;i<=n-1;i++){
if(dp[m][i]==1){
v.push_back(i+1);
}
}
cout<<v.size()<<'\n';
for(auto &t:v){
cout<<t<<" ";
}
cout<<'\n';
}
int main()
{
std::ios::sync_with_stdio(0);
std::cin.tie(0);
int T=1;
cin>>T;
while(T--)
{
solve();
}
return 0;
}
除了动态规划,还可以用set来限制复杂度,让暴力枚举的位置数始终在n以内(因为set去重,不同的位置最多只有n个)
代码(2):
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
typedef long long ll;
const int N=1e3+10,M=998244353;
int n,m,x;
int r[N];
char c[N];
void solve()
{
cin>>n>>m>>x;
for(int i=1;i<=m;i++){
cin>>r[i]>>c[i];
}
set<int> st[2];//开两个set轮流存
int flag=0;
st[flag].insert(x-1);
for(int i=1;i<=m;i++){
while(st[flag].size()){
int t=*st[flag].begin();
if(c[i]!='0'){
st[flag^1].insert(((t-r[i])%n+n)%n);
}
if(c[i]!='1'){
st[flag^1].insert((t+r[i])%n);
}
st[flag].erase(t);
}
flag^=1;//换个set
}
cout<<st[flag].size()<<'\n';
for(auto &t:st[flag]){
cout<<t+1<<" ";
}
cout<<'\n';
}
int main()
{
std::ios::sync_with_stdio(0);
std::cin.tie(0);
int T=1;
cin>>T;
while(T--)
{
solve();
}
return 0;
}
E:Rudolf and k Bridges
题面:
F:Rudolf and Imbalance
题面:
分析:
贪心、二分
只能在一个位置插入d[i]+f[j],让a[i]-a[i-1](i>1)(即间隔gap)的最大值最小
那么只能在最大的gap处插入,其他地方插入答案不变,并且d[i]+f[j]越靠近(a[i]-a[i-1])/2越好,如果将最大的gap分成的两个部分小于第二大的gap,答案为第二大的gap,否则答案为所有的分成的两个部分最大值的最小值
直接枚举d[i]和f[j]时间复杂度O(mk),可以先对f排序,再枚举d[i],二分合适的f[j]((a[i]-a[i-1])/2-d[i]),更新答案,时间复杂度O(mlog k)
代码:
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
typedef long long ll;
const int N=2e5+10,M=1e9+7;
ll n,m,k;
ll a[N],d[N],f[N];
void solve()
{
cin>>n>>m>>k;
for(int i=1;i<=n;i++){//都乘以2可以规避取整的问题
cin>>a[i];
a[i]*=2;
}
for(int i=1;i<=m;i++){
cin>>d[i];
d[i]*=2;
}
for(int i=1;i<=k;i++){
cin>>f[i];
f[i]*=2;
}
ll maxn1=-1,maxn2=-1,l=0,r=0;
for(int i=1;i<=n-1;i++){//找第一和第二大的gap
ll t=a[i+1]-a[i];
if(t>maxn1){
maxn2=maxn1;
maxn1=t;
l=i;
r=i+1;
}else if(t>maxn2){
maxn2=t;
}
}
ll aver=(a[l]+a[r])/2;
sort(f+1,f+k+1);
ll ans=maxn1;
for(int i=1;i<=m;i++){
ll t=lower_bound(f+1,f+k+1,aver-d[i]+1)-f;//二分,+1枚举右侧会比较好处理
if(t>k||(t>1&&abs((aver-d[i])-f[t-1])<abs((aver-d[i])-f[t]))){//修正t
t--;
}else if(t<1){
t++;
}
if(d[i]+f[t]>=a[l]&&d[i]+f[t]<=a[r]){//能进行分隔
ll res=max(a[r]-f[t]-d[i],d[i]+f[t]-a[l]);
ans=min(ans,res);
}
}
ans=max(ans,maxn2);
cout<<ans/2<<'\n';
}
int main()
{
std::ios::sync_with_stdio(0);
std::cin.tie(0);
int T=1;
cin>>T;
while(T--)
{
solve();
}
return 0;
}
G:Rudolf and Subway
题面: