- 吴易繁 的博客
七月暑期集训DAY08——模拟与基础算法专题
- @ 2024-7-16 21:01:39
A. 小田的同余
题目类型:模拟
思路
首先通过题意可得知,m为奇数,而2x%m等于1,那2x的最小数就为m+1,最后就可得出公式:x=(m+1)/2,在这道题目中也不用考虑m=1,因为m的数据范围为3≤m≤1000000000000,但是注意:m要开long long,而最后的结果也要开long long。
代码
#include<bits/stdc++.h>
using namespace std;
int main(){
freopen("mod.in","r",stdin);
freopen("mod.out","w",stdout);
long long m;
cin>>m;
long long x=(m+1)/2;
cout<<x;
return 0;
}
本题代码已AC,下一次继续保持。
B. 小田的奶牛要饿坏啦!!
题目类型:模拟
思路
这道题目可以用ans表示有几天不能吃草,res表示能吃几天草,根据这些再来遍历,每次更新ans,res,最后输出t-ans与0的最大值即可,但是注意:所有的变量都要开long long,在更新最大值的时候也要将0变为long long类型。
代码
#include<bits/stdc++.h>
using namespace std;
int main(){
freopen("cow.in","r",stdin);
freopen("cow.out","w",stdout);
long long n,t,ans=0,res=0;
cin>>n>>t;
for(long long i=1;i<=n;i++){
long long d,b;
cin>>d>>b;
if(res>=d) res+=b;
else ans+=(d-res-1),res=d+b-1;
}
cout<<max((long long)0,t-ans);
return 0;
}
这道题目在写的时候忘写一种特别的情况了了,导致只得了15分,下一次要注意特别的情况。
C. 小田喂猫
题目类型:前缀和加后缀和加二分
思路
这道题如果只用模拟,必定会超时,我们看,其实k天吃的猫粮总数中若猫粮数量大于k,那k天就会吃k次,若猫粮数量小于k,那k天就会吃猫粮的数量,但用这个方法来写代码还是会超时,我们再看可以发现猫粮可以分成两个部分,第一个部分是在k天之内可以吃完,第二个部分是在吃了k天后还有剩余的,那么在他们之间就必定有一个整数k,来分割他们两部分,而必定会满足这样一个性质:k与k的前面必定在k天之内可以吃完,在k的后面必定在吃了k天后还有剩余的,我们要可以用二分找到这个数,那就是找出<=k的最后一个数,那就要用二分的第二个模板,除此之外,我们还要使用前缀和来计算区间和,然后用二分找到这个数,最后将他们两加起来输出即可,但是数据不一定保证升序,所以在处理之前还要将数据进行升降排序排序,注意:为了方便我们可以用pair,但是在输入的时候我们要将营养值定为pair的第二项,将数量定为pair的第一项,因为我们要看的不是营养值,而是数量,在排序的时候也会看第一项的值(也就是数量),再其次就是要开long long.
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
pair<long,long> a[N];
long long s[N],b[N];
int k;
long long ef(int l,int r){
while(l<r){
long long mid=(l+r+1)/2;
if(a[mid].first<=k) l=mid;
else r=mid-1;
}
return l;
}
int main(){
freopen("cat.in","r",stdin);
freopen("cat.out","w",stdout);
int n;
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i].second;
for(int i=1;i<=n;i++) cin>>a[i].first;
sort(a+1,a+n+1);
for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i].first*a[i].second;
for(int i=n;i>=1;i--) b[i]=b[i+1]+a[i].second;
int q;
cin>>q;
while(q--){
cin>>k;
long long d=ef(0,n);
cout<<s[d]+b[d+1]*k<<endl;
}
return 0;
}
这道题目在写的时候写了暴力,只拿了30分,下次要想一想AC的写法。
D. 小田的打字练习
题目类型:模拟
思路
这道题目就是一个大模拟,只需注意处理退格键,其他按题目要求来就行。
代码
#include<bits/stdc++.h>
using namespace std;
int main(){
freopen("key.in","r",stdin);
freopen("key.out","w",stdout);
string s;
vector<char> a,b;
while(getline(cin,s)){
if(s=="EOF") break;
if(s==" ") continue;
for(int i=0;i<s.size();i++){
if(s[i]=='<'&&s[0]!='<') a.pop_back();
if(s[i]!='<') a.push_back(s[i]);
}
a.push_back('>');
}
while(getline(cin,s)){
if(s=="EOF") break;
if(s=="") continue;
for(int i=0;i<s.size();i++){
if(s[i]=='<'&&s[0]!='<') b.pop_back();
if(s[i]!='<') b.push_back(s[i]);
}
b.push_back('>');
}
int cnt=0;
for(int i=0,j=0;i<a.size()&&j<b.size();i++,j++){
while(a[i]=='>'&&b[j]!='>') j++;
while(a[i]!='>'&&b[j]=='>') i++;
if(a[i]==b[j]&&a[i]!='>') cnt++;
}
double n;
cin>>n;
n/=60;
cout<<(long long)(cnt/n+0.5);
return 0;
}
这道题目在写的时候忘写一种特别的情况了了,导致只得了45分,下一次要注意特别的情况。
E. 小田切蛋糕
题目类型:前缀和加二分
思路
对于这道题目,我们先可以一个一个去枚举巧克力碎屑的数量,再来计算是否可行,所以我们不妨用前缀和来写,但是我们会发现,这么写是会超时的,所以我们还需要用二分。
代码
#include<bits/stdc++.h>
using namespace std;
int d[510][510],s[510][510],r,c,a,b;
int check(int mid){
int l1=0,r1=0;
for(int i=1;i<=r;i++){
int x=0,y=0;
for(int j=1;j<=c;j++){
int f=s[i][j]-s[i][x]-s[r1][j]+s[r1][x];
if(f>=mid) x=j,y++;
if(y==b){
l1++,r1=i;
break;
}
}
if(l1==a)return 1;
}
return 0;
}
int ef(int e){
int l=0,r=e;
while(l<r){
int mid=l+r+1>>1;
if(check(mid)) l=mid;
else r=mid-1;
}
return l;
}
int main(){
freopen("cake.in","r",stdin);
freopen("cake.out","w",stdout);
int e;
cin>>r>>c>>a>>b;
for(int i=1;i<=r;i++)
for(int j=1;j<=c;j++){
cin>>d[i][j];
s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+d[i][j];
if(i==r&&j==c) e=s[i][j];
}
int cnt=ef(e);
cout<<cnt;
return 0;
}
这道题目完全没有思路,所以就放弃了,输出了个-1骗了十五分,下一次不能轻易放弃。
F. 小田想困住奶牛
题目类型:模拟
思路
每次模拟一下,只要让牛往左走或者让牛往右走即可,最后判断一下,若ans没变,输出-1,否则输出0与ans的最大值。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
pair<int,int> a[N];
int main(){
freopen("cow.in","r",stdin);
freopen("cow.out","w",stdout);
int n,b,nl,nr;
cin>>n>>b;
for(int i=1;i<=n;i++) cin>>a[i].second>>a[i].first;
sort(a+1,a+1+n);
int ans=1e9;
for(int i=1;i<=n;i++){
if(a[i].first>b){
nr=i;
nl=i-1;
break;
}
}
long long l=nl,r=nr;
if(b>a[n].first||b<a[1].first){
cout<<-1;
return 0;
}
while(l>=1){
while(r<=n&&a[r].first-a[l].first>a[r].second) r++;
if(r>n) break;
ans=min(ans,a[r].first-a[l].first-a[l].second);
l--;
}
l=nl,r=nr;
while(r<=n){
while(l>=1&&a[r].first-a[l].first>a[l].second) l--;
if(l<1) break;
ans=min(ans,a[r].first-a[l].first-a[r].second);
r++;
}
if(ans==1e9) cout<<-1;
else cout<<max(0,ans);
return 0;
}
这道题目完全没有思路,所以就放弃了,下一次不能轻易放弃。