这是我大一第一次参加CCPC,只拿到了一个省铜······
还需继续努力in---
补题环节:
Problem A. Once In My Life
题目描述:给定两个数n和d,找到一个正整数k,使得二者的乘积n·k是幸运数。
解题思路:幸运数包含1到9,所以我们可以构造一个数N为1234567890+d,那么N就一定是幸运数,这时我们只需要把N作为n的前缀,然后减去(N作为n的前缀的数%n),那么N就一定可以整除n,最后输出这个数/n即可。
实现代码:
#include<bits/stdc++.h>
#define int long long
#define endl "\n"
#define fi first
#define se second
#define PII pair<int,int>
using namespace std;
const int N=1e6+5;
int a[N];
const int M=1234567890;
void solve(){
int n,d;
cin >> n >> d;
int m=M+d;
int len=to_string(n).size();
m=m*pow(10,len);
m+=n;
m-=m%n;
cout << m/n << endl;
return ;
}
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int t=1;
cin >> t;
while(t--) solve();
return 0;
}
Problem B. 扫雷 1
题意描述:进行n轮游戏,每轮获得一个金币,同时每轮也可以无限次购买地雷探测器,给出地雷探测器的价格,问最多可以买多少个探测器。
解题思路:贪心策略+双指针:先给每轮的地雷探测器进行升序排序并且统计这些价格的数量,每轮游戏找最便宜的地雷探测器,若不满足减去这个数量,满足则全买这个地雷探测器,同时也减去这个数量,当最便宜的地雷探测器的数量为0时,指针向右移动,最后输出答案即可。
实现代码:
#include<bits/stdc++.h>
#define int long long
#define endl "\n"
#define fi first
#define se second
#define PII pair<int,int>
using namespace std;
const int N=2e5+5;
int a[N],b[N];
map<int,int> m;
void solve(){
int n;
cin >> n;
for(int i=0;i<n;++i){
cin >> a[i];
b[i]=a[i];
m[a[i]]++;
}
sort(b,b+n);
int p=0,ans=0,cnt=0;
for(int i=0;i<n;++i){
cnt++;
if(a[i]==b[p]){
ans+=cnt/a[i];
cnt%=a[i];
}
m[a[i]]--;
if(i==n-1) break;//当i指针循环到最后时,直接break,否则下面的while语句会无限执行
while(m[b[p]]==0) p++;
}
cout << ans;
return ;
}
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int t=1;
//cin >> t;
while(t--) solve();
return 0;
}
Problem F. 优秀字符串
题意描述:一个优秀的字符串满足以下条件:
• S 的长度|S|恰好为5;
• S 的第三个字符与第五个字符相同
• S 的前四个字符互不相同。
求优秀字符串的数量。
解题思路:签到题,直接暴力模拟就行。
实现代码:
#include<bits/stdc++.h>
#define int long long
#define endl "\n"
#define fi first
#define se second
#define PII pair<int,int>
using namespace std;
const int N=1e6+5;
//int a[N];
int ans=0;
void solve(){
string s;
cin >> s;
map<char,int> v;
if(s.size()!=5) return;
if(s[2]!=s[4]) return;
for(int i=0;i<s.size()-1;++i){
if(v[s[i]]) return ;
v[s[i]]++;
}
ans++;
return ;
}
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int t=1;
cin >> t;
while(t--) solve();
cout << ans;
return 0;
}
Problem H. 随机栈
题目描述:有2n次操作,每次操作有两种情况:
-1:从集合里面取出一个数
非-1:将这个数存入集合里面
求最后取出来的数组满足递增(小于等于后一项)的概率,然后对这个概率进行取模处理。
解题思路:首先我们可以开一个最小堆模拟集合,因为每次取出的数必须是集合里面最小的数,否则就不满足题意,堆中的元素总数为分母,当前队头的最小元素的数量即为分子,该数量可以用map来记录,计算不同分数的积并进行取模,最后将分母进行快速幂的逆元,然后乘上分子在取模一次即可。
实现代码:
#include<bits/stdc++.h>
#define int long long
#define endl "\n"
#define fi first
#define se second
#define PII pair<int,int>
using namespace std;
const int N=2e5+5;
int a[N];
int cnt[N];
priority_queue<int,vector<int>,greater<int>> q;
const int mod=998244353;
int quick_mi(int a,int b){
int ans=1;
while(b){
while(b%2==0) a=a*a%mod,b/=2;
ans=ans*a%mod,b-=1;
}
return ans;
}
void solve(){
int n;
cin >> n;
int fz=1,fm=1;
int maxn=0;
for(int i=1;i<=n*2;++i){
int x;
cin >> x;
if(x!=-1){
q.push(x),cnt[x]++;
if(x<maxn){
cout << 0 << endl;
return ;
}
}
else{
fz=(fz*cnt[q.top()])%mod;
fm=(fm*q.size())%mod;
maxn=max(maxn,q.top());
cnt[q.top()]--,q.pop();
}
}
fm=quick_mi(fm,mod-2)%mod;
int ans=(fz*fm)%mod;
cout << ans << endl;
return ;
}
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int t=1;
//cin >> t;
while(t--) solve();
return 0;
}
Problem J. 排列与合数
题目描述:给出一个五位数字,重排后在没有前导零的情况下是否可能出现合数;
解题思路:当这个数含偶数必然是合数,而当这个数全为奇数时由样例可知也一定为合数,所以不可能出现不为合数的情况(不需要考虑-1),那么暴力判断(先考虑含0的情况)即可。
实现代码:
#include<bits/stdc++.h>
#define int long long
#define endl "\n"
#define fi first
#define se second
#define PII pair<int,int>
using namespace std;
const int N=2e5+5;
int a[N],b[N];
map<int,int> m;
void solve(){
char ch1,ch2,ch3,ch4,ch5;
cin >> ch1 >> ch2 >> ch3 >> ch4 >> ch5;
if(ch1=='0'){
cout << ch2 << ch3 << ch4 << ch5 << ch1<< endl;
return ;
}
if(ch2=='0'){
cout << ch1 << ch3 << ch4 << ch5 << ch2<< endl;
return ;
}
if(ch3=='0'){
cout << ch2 << ch1 << ch4 << ch5 << ch3<< endl;
return ;
}
if(ch4=='0'){
cout << ch2 << ch3 << ch1 << ch5 << ch4<< endl;
return ;
}
if(ch5=='0'){
cout << ch2 << ch3 << ch4 << ch1 << ch5<< endl;
return ;
}
if((ch1-'0')%2==0){
cout << ch2 << ch3 << ch4 << ch5 << ch1<< endl;
return ;
}
if((ch2-'0')%2==0){
cout << ch1 << ch3 << ch4 << ch5 << ch2<< endl;
return ;
}
if((ch3-'0')%2==0){
cout << ch2 << ch1 << ch4 << ch5 << ch3<< endl;
return ;
}
if((ch4-'0')%2==0){
cout << ch2 << ch3 << ch1 << ch5 << ch4<< endl;
return ;
}
if((ch5-'0')%2==0){
cout << ch2 << ch3 << ch4 << ch1 << ch5<< endl;
return ;
}
else cout << "97531" << endl;
return ;
}
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int t=1;
cin >> t;
while(t--) solve();
return 0;
}
M. 有效算法
题意描述:给出长度为n的数组a,b,对每个ai进行以下操作:
将ai 变成满足|ai−x|≤k×bi 的任意整数x。
求满足操作下的最小的非负整数k。
解题思路:对k进行二分即可,依照题目的操作,我们可以得到下列两个式子:
ai≥x: ai−k×bi≤x<=ai
ai<=x: ai<=x<=k×bi+ai
因此可以求出x的区间,最后套用二分求左边界的模板即可。
实现代码:
#include<bits/stdc++.h>
#define int long long
#define endl "\n"
#define fi first
#define se second
#define PII pair<int,int>
using namespace std;
const int N=1e6+5;
vector<int> a,b;
int n;
int check(int k){
int minn=1e9+5,maxn=0;
for(int i=1;i<=n;++i){
minn=min(minn,a[i]+k*b[i]);
maxn=max(maxn,a[i]-k*b[i]);
if(maxn>minn) return 0;
}
return 1;
}
void solve(){
cin >> n;
a.resize(n+1),b.resize(n+1);
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;
while(l<r){
int mid=l+r>>1;
if(check(mid)) r=mid;
else l=mid+1;
}
cout << l << endl;
return ;
}
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int t=1;
cin >> t;
while(t--) solve();
return 0;
}