//Solve函数结合末尾模板
F.优秀字符串
题意:
优秀字符串:长度为5,第三个字符与第五个字符相同,S 的前四个字符互不相同。
给定n个字符串,判断优秀字符串数量。
思路:
先判断长度,在判断第三个和第五个字符,for循环判断前四个字符是否相同
Solved:
int solve()
{
string s;cin>>s;
int len=s.size();
if(len!=5) return 0;
if(s[2]!=s[4]) return 0;
for(int i=0;i<=3;i++){
for(int j=i+1;j<=3;j++)
if(s[i]==s[j]) return 0;
}
return 1;
}
// while(n--){
// if(solve()==1){
// sum++;
// }
// }
// cout<<sum;
J.排列与合数
题意:
给定一个n,判断是否为合数,if合数就输出,else if重新排序为合数后输出,else -1。
保证n的各个数位互不相同。
合数:除了1和他本身,还能被其他数整除。
思路:
n的各个数位互不相同,可得出末尾偶数0,2,4,6,8均为2的倍数,末尾为5为5的倍数,此时还剩4个数,n保证5位,所以排序后一定可以构成合数。
直接判断末尾是不是0,2,4,6,8,5,是直接输出,不是就从前四位中找一个0,2,4,6,8,5与末尾交换位置即可。
不用考虑前导0,如果末尾有0直接输出,题目给出n不含前导0,交换0只会到末尾
Solved:
void solve()
{
string s;cin>>s;
if(s[4]=='0'||s[4]=='2'||s[4]=='4'||s[4]=='6'||s[4]=='8'||s[4]=='5'){
cout<<s<<endl; return;
}
else{
for(int i=0;i<=3;i++){
if(s[i]=='0'||s[i]=='2'||s[i]=='4'||s[i]=='6'||s[i]=='8'||s[i]=='5'){
swap(s[i],s[4]);
break;
}
}
cout<<s<<endl; return;
}
}
B. 扫雷 1
题意:
每个回合给一金币(money),并给出一个探测仪价格(cost),可在该回合买探测器,求一轮游戏最多获得多少探测器。
思路
定义结构体将cost和money连接,按照cost升序排序,在每个最低cost时买入探测器,更新每轮金币(此时我将每轮花费存入t,cnt为上一轮剩余的钱数,每轮money=money-t+cnt更新,并归零cnt),如果可以买入探测器,就在ans+本轮个数。
Solved:
const int N=2e5+10;
struct st
{
int c,m;//c:cost,探测器价格,m:money本轮金币数
}a[N];
int cmp(st p,st q)
{
if(p.c<q.c) return 1;
return 0;
}
signed solve()
{
int n;cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i].c;
a[i].m=i;
}
sort(a+1,a+1+n,cmp);
// for(int i=1;i<=n;i++){
// cout<<a[i].c<<" "<<a[i].m<<endl;
// }
int ans=0;//购买总量
int cnt=0;//上一轮购买完剩余金币
int t=0;//每次购买后的花费
for(int i=1;i<=n;i++){
a[i].m=a[i].m-t+cnt;//利用t和cnt更新每轮剩余金币数
cnt=0;//重置余数
if(a[i].m>=a[i].c)//如果本轮money>=cost可以购买
{
ans+=a[i].m/a[i].c;//买
cnt+=a[i].m%a[i].c;//剩余金币
t+=a[i].m/a[i].c*a[i].c;//更新总花费
}
}
cout<<ans; return;
A.Once In My Life
题意:
幸运数:数位包含1~9,并且至少包含两位d。
给定一个正整数n,希望找到一个k使得n*k为幸运数。
思路:
根据数据范围n<1e8,longlong 19位,所以可以先构造kk=1234567890+d,并将n加到kk的后面去构造n的倍数找k(如果不加n直接除n,可能使1234567890+d(幸运数序列)造成影响)。
Solved:
void solve()
{
int n,d;cin>>n>>d;
int kk=1234567890+d;//构造幸运数序列
int len=log10(n)+1;//int len=to_string(n).size();
kk*=pow(10,len);//将n+到k后
kk+=n;
cout<<kk/n<<endl;//输出k
}
M.有效算法
题意:
给出ai,bi
ai可以变成满足|ai−x|≤k×bi的任意整数x,求出最小的k。
去绝对值后
ai-x<=k * bi ,ai-x>=-k * bi。
题目中数据范围很大,因此k不能从1~n按顺序找,应该用二分
找到k后验证x的取值范围,x>=ai-k * bi ,x<=ai+k * bi.
遍历a和b数组
如果左端点的最大值大于右端点的最小值,则k不成立,left=mid+1(在mid右侧找k)
如果遍历完k成立,则 right=mid (在mid左侧找k)
Solved:
const int N=3e5+10;
int a[N],b[N];
int n;
int num(int k)
{
int mx=INT_MIN,mi=INT_MAX;
for(int i=1;i<=n;i++){
mx=max(mx,a[i]-k*b[i]);
mi=min(mi,a[i]+k*b[i]);
if(mx>mi)
return 0;
}
return 1;
}
void solve()
{
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
cin>>b[i];
}
int l=0,r=1e9,mid;
while(l<r){
mid=l+r>>1;
if(num(mid)==1){
r=mid;
}
else{
l=mid+1;
}
}
cout<<l<<endl;
}
H.随机栈
题意:
有一个随机的栈,给出数字如果-1则从栈中随机取出数字,否则将数字存入栈中。
求从一个栈中顺序取出的数字排成升序的概率,要求结果逆元
费马小定理:如果mod p,p为一个质数,b的p-2次方就是b的乘法逆元
思路:
求排成升序的概率,可以算出每次都取栈中最小数字的概率,取出最小数字可用大根堆实现,开book数组存最小数字在大根堆中出现次数,本次取出概率即为出现次数/大根堆总个数
const int mod=998244353;
const int N=2e5+10;
int a[N],book[N];
int qmf(int s,int y)
{
int res=1;
while(y){
if(y&1){
res=res*s%mod;
}
s=s*s%mod;
y/=2;
}
return res;
}
void solve()
{
priority_queue<int,vector<int>,greater<int>> q;
int n;cin>>n;
int mx=0;
int fz=1,fm=1;
for(int i=1;i<=2*n;i++){
int x;cin>>x;
if(x!=-1){
q.push(x);
book[x]++;
}
else{
int t=q.top();
if(t<mx){
cout<<"0"<<endl;
return ;
}
fz=fz*book[t]%mod;
fm=fm*q.size()%mod;
book[t]--;
q.pop();
mx=t;
}
}
int ans=qmf(fz,mod-2)*qmf(fm,mod-2)%mod;
cout<<ans;
}
模板
#include <bits/stdc++.h>
using namespace std;
#define int long long
void solve()
{
}
signed main()
{
std::ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int n;cin>>n;
while(n--){
solve();
}
return 0;
}