A. Thorns and Coins
题意
长度为n的字符串,其中@表示金币,*表示荆棘,每次可以移动1个或2个长度,不可以走到有荆棘的位置上,求可以获得金币的最大数量
分析
在遇到连续的两个荆棘前,我们可以一直收集金币,枚举即可
代码
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
//#include<queue>
//#include<map>
//#include<vector>
//#include<set>
//#include<deque>
//#include<bitset>
//#include<functional>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
typedef pair<int,int>PII;
void solve()
{
int n;
string s;
cin>>n>>s;
ll ans=0;
for(int i=0;i<s.size();i++)
{
if(s[i]=='*' && s[i+1]=='*') break;
if(s[i]=='@') ans++;
}
cout<<ans<<endl;
}
int main()
{
int t;cin>>t;
while(t--) solve();
return 0;
}
B. Chaya Calendar
题意
有n个符号,第i个符号每隔a[i]年出现一次,如果第i个符号出现在第x年,那么第i+1个符号只能出现在x年之后(每年只能接收一个符号),求接收全部符号发生在第几年
分析
由于每个符号循环出现,而且每年只能接受一个符号,分情况讨论
1.下一个符号出现的年份在上一个符号出现年份之后
此时只需要等待到下一个符号出现的年份即可
2.下一个符号出现的年份在上一个符号出现年份之前
那么需要等待到k*a[i+1]年,其中k代表满足k*a[i+1]>a[i]成立的最小的k,二分出最小的k即可
分情况计算出现年份,不断更新上一个符号出现年份即可
代码
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
#include<vector>
//#include<queue>
#include<stack>
//#include<set>
//#include<deque>
//#include<bitset>
//#include<functional>
#define ll long long
#define inf 0x3f3f3f3f
#define lc p<<1
#define rc p<<1|1
using namespace std;
typedef pair<int,int>PII;
void solve()
{
int n;cin>>n;
vector<ll>f(n+1);
for(int i=1;i<=n;i++) cin>>f[i];
ll last=f[1];
for(int i=2;i<=n;i++)
{
if(f[i]<=last+1)
{
int l=0,r=1e9;
while(l+1<r)
{
int mid=(l+r)>>1;
if(mid*f[i]<=last) l=mid;
else r=mid;
}
last=r*f[i];
}
last=max(last,f[i]);
}
cout<<last<<endl;
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t;cin>>t;
while(t--) solve();
return 0;
}
C. LR-remainders
题意
您将得到一个长度为 n的数组 a 、一个正整数 m 和一个长度为 n的命令字符串。每个命令都是字符“L”或字符“R”。
按照在字符串 s 中写入命令的顺序处理所有 n 命令。
命令的处理过程如下:
-首先,输出数组 a 的所有元素的乘积除以 m 的余数。
-然后,如果命令是'L',则从数组 a 中删除最左边的元素,如果命令是'R',
从数组 a中删除最右边的元素。请注意,每次移动后,数组 a的长度将减少 1 ,并且在处理所有命令后,它将为空。
分析
t最大为1e4,n最大为2e5,a[i]最大为1e4,如果直接将数组元素全部乘起来操作会爆int,如果开long long(从wa2变成了wa3)也会爆,考虑高精度(可能会tle),也可以逆向思维,倒过来做,由于已知删除顺序,我们从最后一个删除的数开始,不断还原原数组此时的乘积,然后将答案存入答案数组中,最后倒序输出即可
由于是倒序操作,可以使用stack方便存储
代码
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
#include<vector>
//#include<queue>
#include<stack>
//#include<set>
//#include<deque>
//#include<bitset>
//#include<functional>
#define ll long long
#define inf 0x3f3f3f3f
#define lc p<<1
#define rc p<<1|1
using namespace std;
typedef pair<int,int>PII;
void solve()
{
int n,m;cin>>n>>m;
vector<int>f(n+1);
for(int i=1;i<=n;i++) cin>>f[i];
string s;cin>>s;
stack<int>sta;
int l=1,r=n;
for(int i=0;i<n;i++)
{
if(s[i]=='L') sta.push(f[l++]);
else sta.push(f[r--]);
}
vector<ll>ans(n+1);
ll t=1;
for(int i=n;i>=1;i--)
{
t=t*sta.top()%m;
sta.pop();
ans[i]=t;
}
for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
cout<<endl;
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t;cin>>t;
while(t--) solve();
return 0;
}
D. Card Game
题意
有四种花色的卡牌,分别用C,S,D,H代表,每种花色有2-9八张,四种花色共有32张卡牌,每局游戏给出一种花色作为王牌花色,每轮游戏第一个人打出一张卡牌,第二个人只能打出比他大的卡牌,该轮结束,关于卡牌大小规定如下
1.相同花色时,数字越大的卡牌越大
2.王牌花色卡牌比其他卡牌大,不论点数是多少
3.王牌花色卡牌比较时,点数大的卡牌大
现给定n,代表该场游戏已经进行多少轮,和王牌花色,以及2*n张卡牌代表其花色和点数,如果存在合理的游戏回合,输出每轮两人打出的卡牌,若不存在输出IMPOSSIBLE
分析
最讨厌模拟的一集,由于相同卡牌花色点数唯一,所以当相同花色卡牌出现2张时,一定可以消掉,我们可以用map记录每种花色上次出现的点数,当有花色出现两次时,将其调整为小点数在前大点数在后的格式加入ans中,将王牌花色卡牌的点数单独加入一个容器中。此操作结束之后,除去王牌花色,其余花色最多只剩一张牌没有消去,如果此时王牌花色的牌数小于其余花色的牌数,那么该轮不合理,输出impossible,否则我们将王牌花色的牌按点数从小到大排序,将其余花色的牌用王牌花色消去后加入ans,剩下的王牌花色牌分别消去加入ans即可
代码
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
#include<vector>
//#include<queue>
#include<stack>
#include<set>
//#include<deque>
//#include<bitset>
//#include<functional>
#define ll long long
#define inf 0x3f3f3f3f
#define lc p<<1
#define rc p<<1|1
using namespace std;
typedef pair<int,int>PII;
void solve()
{
int n;char king;
cin>>n>>king;
vector<int>v;
vector<string>ans;
n*=2;
map<char,int>mp;
for(int i=1;i<=n;i++)
{
string s;cin>>s;
if(s[1]==king) v.emplace_back(s[0]-'0');
else
{
string ss=s;
if(mp[ss[1]])
{
s+=" ";
//cout<<s<<endl;
s+=mp[ss[1]]+'0';
//cout<<s<<endl;
s+=ss[1];
//cout<<s<<endl;
if(s[0]>s[3]) swap(s[0],s[3]);
ans.emplace_back(s);
mp[ss[1]]=0;
}
else mp[ss[1]]=ss[0]-'0';
}
}
ll res=0;
if(mp['C']!=0) res++;
if(mp['S']!=0) res++;
if(mp['D']!=0) res++;
if(mp['H']!=0) res++;
//cout<<res;
if(v.size()<res)
{
cout<<"IMPOSSIBLE"<<'\n';
return;
}
sort(v.begin(),v.end());
//for(auto c:ans) cout<<c<<" ";
string t;
for(auto c:v)
{
if(mp['S']!=0 || mp['C']!=0 || mp['D']!=0 || mp['H']!=0)
{
if(mp['C']!=0 && t.size()<2) t+=mp['C']+'0',t+='C',mp['C']=0;
else if(mp['S']!=0 && t.size()<2) t+=mp['S']+'0',t+='S',mp['S']=0;
else if(mp['D']!=0 && t.size()<2) t+=mp['D']+'0',t+='D',mp['D']=0;
else if(mp['H']!=0 && t.size()<2) t+=mp['H']+'0',t+='H',mp['H']=0;
//cout<<t<<endl;
t+=" ";
t+=c+'0';
t+=king;
ans.emplace_back(t);
t="";
}
else
{
t+=c+'0';
t+=king;
if(t.size()==2) t+=" ";
if(t.size()==5)
{
ans.emplace_back(t);
t="";
}
}
}
for(auto c:ans) cout<<c<<endl;
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t;cin>>t;
while(t--) solve();
return 0;
}
E. Final Countdown
题意
给定一个长度为n的整数a,a每次减少1要经过t秒,t为a变为a-1所改变的位数,例100变为99需要2秒,因为其改变了两位;1100变为1099需要3秒,求当a减少为0时,需要经过多少秒
分析
最不会数学的一集,结论是12345需要12345+1234+123+12+1秒,1234需要1234+123+12+1秒,每次除10相加,直到为0,由于n最大为4e5,需要高精度,观察可以发现每一位数只加其前面的数,
例如
12345
1234
123
12
1
我们可以使用前缀和数组记录每一位数加完之后的结果,然后倒序模拟进位,在输出时过滤掉前导0即可
代码
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
#include<vector>
//#include<queue>
#include<stack>
//#include<set>
//#include<deque>
//#include<bitset>
//#include<functional>
#define ll long long
#define inf 0x3f3f3f3f
#define lc p<<1
#define rc p<<1|1
using namespace std;
typedef pair<int,int>PII;
void solve()
{
int n;cin>>n;
string s;cin>>s;
s=" "+s;
vector<ll>pre(n+1);
for(int i=1;i<=n;i++) pre[i]=pre[i-1]+s[i]-'0';
for(int i=n;i>=0;i--)
{
pre[i-1]+=pre[i]/10;
pre[i]=pre[i]%10;
//cout<<pre[i];
}
int flag=0;
for(int i=0;i<=n;i++)
{
//cout<<pre[i];
if(pre[i]!=0) flag=1;
if(flag) cout<<pre[i];
}
cout<<endl;
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t;cin>>t;
while(t--) solve();
return 0;
}