1.1236. 递增三元组
方法一:二分要在ac两个数组中找严格小于或大于b[i]的第一个位置【经过我与大佬的苦苦钻研才改好/(ㄒoㄒ)/~~】
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100010;
ll a[N],b[N],c[N];
ll ax[N],cx[N];
ll cnt[N],s[N];
ll n;
ll finda(ll a[],ll u)
{
ll l=1,r=n;
ll cnt = 0;
while(l<r)
{
ll mid=l+r+1>>1;
if(a[mid] < u) l=mid;
else r=mid-1;
}
if(a[l]>=u) return 0;
else return l;
}
ll findc(ll c[],ll u)
{
ll l=1,r=n;
while(l<r)
{
ll mid=l+r>>1;
if(c[mid] > u) r=mid;
else l=mid + 1;
}
if(c[r] <= u) return 0;
else return n - r + 1;
}
int main()
{
cin>>n;
for(ll i=1;i<=n;i++) scanf("%lld",&a[i]);
for(ll i=1;i<=n;i++) scanf("%lld",&b[i]);
for(ll i=1;i<=n;i++) scanf("%lld",&c[i]);
sort(a+1,a+n+1);sort(c+1,c+n+1);
// for(int i=1;i<=n;i++) cout<<c[i]<<endl;
ll res=0;
for(ll i=1;i<=n;i++)
{
ax[i]=finda(a,b[i]);
//cout<<ax[i]<<endl;
cx[i]=findc(c,b[i]);
//cout<<cx[i]<<endl;
res+=ax[i]*cx[i];
}
cout<<res<<endl;
return 0;
}
方法二:前缀和:记录前面小于b[i]的个数一共有多少,与题意恰好吻合【妙啊】
#include <bits/stdc++.h>
using namespace std;
const int N=100010;
int a[N],b[N],c[N];
int ax[N],cx[N];
int cnt[N],s[N];
int n;
int main()
{
cin>>n;
for(int i=1;i<=n;i++) scanf("%d",&a[i]),a[i]++;
for(int i=1;i<=n;i++) scanf("%d",&b[i]),b[i]++;
for(int i=1;i<=n;i++) scanf("%d",&c[i]),c[i]++;
for(int i=1;i<=n;i++) cnt[a[i]]++;
for(int i=1;i<N;i++) s[i]=s[i-1]+cnt[i];
for(int i=1;i<=n;i++) ax[i]=s[b[i]-1];
memset(cnt,0,sizeof cnt);
memset(s,0,sizeof s);
for(int i=1;i<=n;i++) cnt[c[i]]++;
for(int i=1;i<N;i++) s[i]=s[i-1]+cnt[i];
for(int i=1;i<=n;i++) cx[i]=s[N-1]-s[b[i]];
long long res=0;
for(int i=1;i<=n;i++)
{
res+=(long long)ax[i]*cx[i];
}
cout<<res<<endl;
return 0;
}
2.1210. 连号区间数
连号区间的性质:区间的max-min==下标之差!
#include <bits/stdc++.h>
using namespace std;
const int N=10005,INF=1e9;
int a[N];
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
int res=0;
for(int i=1;i<=n;i++)
{
int maxx=-INF,minx=INF;
for(int j=i;j<=n;j++)
{
maxx=max(maxx,a[j]);
minx=min(minx,a[j]);
if(maxx-minx==j-i) res++;
}
}
cout<<res<<endl;
return 0;
}
3.1204错误票据
乍一看:这水题\偷笑;仔细想:map?桶排?臣妾做不到啊/(ㄒoㄒ)/~~
值得学习的地方是对输入的处理:
(1)getline
(2)stringstream
相关资料链接:①②③
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n;
int a[N];
int main()
{
int cnt;
cin>>cnt;
string line;
getline(cin,line);//吃回车
while(cnt--)
{
getline(cin,line);//接收空格读入一个流
stringstream ssin(line);//ssin代替cin接管line流里面的数据
while(ssin>>a[n]) n++;//从ssin找出a[n],并完成数据类型的自动转化
}
sort(a,a+n);
n--;
int res1,res2;
for(int i=1;i<=n;i++)
if(a[i]==a[i-1]) res2=a[i];
else if(a[i]==a[i-1]+2) res1=a[i]-1;
printf("%d %d\n",res1,res2);
return 0;
}
4.466. 回文日期
如果按照“常规思路”写会超时,所以本题采取的策略是:
①先枚举回文数(而且只枚举前四位,后四位直接翻过去)
②判断当前所枚举的日期是否在范围内
③最后判断日期是否合法:年月日分别取出来判断,最后考虑二月
tip:(1)闰年:leap=year%4== 0&&year%100!=0||year%400==0;
(2)优先级:!>&&>||
#include <bits/stdc++.h>
using namespace std;
int days[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
bool check_valid(int date)
{
int year=date/10000;
int month =date%10000/100;
int day=date%100;
if(month==0||month>12) return false;
if(day==0||month!=2&&day>days[month]) return false;
if(month==2)
{
int leap=year%100&&year%4==0||year%400==0;
if(day>28+leap) return false;
}
return true;
}
int main()
{
int date1,date2;
cin>>date1>>date2;
int res=0;
for(int i=1000;i<10000;i++)
{
int date=i,x=i;
//创造回文串
for(int j=0;j<4;j++) {date=date*10+x%10;x/=10;}
if(date1<=date&&date<=date2&&check_valid(date)) res++;
}
cout<<res<<endl;
return 0;
}
5.1219. 移动距离
模拟题:让我情不自禁想到蛇形矩阵(以及被其支配的恐惧),然后惊奇地发现贪吃蛇解法被我忘记了(⊙﹏⊙)(还不去复习)
tips:
①两种距离:
曼哈顿距离:d1=|x1-x2|+|y1-y2|;【本题】
欧几里得距离:d2=sqrt(
(
x
1
−
x
2
)
2
(x1-x2)^2
(x1−x2)2+
(
y
1
−
y
2
)
2
(y1-y2)^2
(y1−y2)2)
②所有数字在输入时的编号-1
③行号:n/w,m/w ; 列号:n%w,m%w,奇数行就翻转
#include <bits/stdc++.h>
using namespace std;
int main()
{
int w,m,n;
cin>>w>>m>>n;
m--,n--;
int x1=m/w,x2=n/w;
int y1=m%w,y2=n%w;
if(x1%2) y1=w-1-y1;
if(x2%2) y2=w-1-y2;
cout<<abs(x1-x2)+abs(y1-y2)<<endl;
return 0;
}
6.1229.日期问题
手写版,好麻烦啊好麻烦,排序,输出,输入搞得我头大;数据太水了,被我混过去了
#include <bits/stdc++.h>
using namespace std;
int days[13]= {0,31,28,31,30,31,30,31,31,30,31,30,31};
bool check_valid(int year,int month,int day)
{
if(year>2059||year<1960)
return false;
if(month==0||month>12)
return false;
if(day==0||month!=2&&day>days[month])
return false;
if(month==2)
{
int leap=year%100&&year%4==0||year%400==0;
if(day>28+leap)
return false;
}
return true;
}
void nian(int a,int tou,int b,int c)
{
a+=tou*100;
if(check_valid(a,b,c))
{
if(b>=1&&b<=9&&c>=1&&c<=9)
printf("%d-0%d-0%d\n",a,b,c);
else if(b>=1&&b<=9&&c>9)
printf("%d-0%d-%d\n",a,b,c);
else if(b>9&&c>=1&&c<=9)
printf("%d-%d-0%d\n",a,b,c);
else
printf("%d-%d-%d\n",a,b,c);
}
}
int main()
{
int a,b,c;
char st;
cin>>a>>st>>b>>st>>c;
//sort(a,a+3);
if(a<=b&&b<=c)
{
if(a==b&&b==c)
{
nian(a,19,b,c);
nian(a,20,b,c);
return 0;
}
nian(a,19,b,c);
nian(c,19,a,b);
nian(c,19,b,a);
nian(a,20,b,c);
nian(c,20,a,b);
nian(c,20,b,a);
}
else if(a<c&&c<=b)
{
nian(a,19,b,c);
nian(c,19,a,b);
nian(c,19,b,a);
nian(a,20,b,c);
nian(c,20,a,b);
nian(c,20,b,a);
}
else if(b<=a&&a<c)
{
nian(a,19,b,c);
nian(c,19,b,a);
nian(c,19,a,b);
nian(a,20,b,c);
nian(c,20,b,a);
nian(c,20,a,b);
}
else if(c<=a&&a<b)
{
nian(c,19,a,b);
nian(c,19,b,a);
nian(a,19,b,c);
nian(c,20,a,b);
nian(c,20,b,a);
nian(a,20,b,c);
}
else if(b<c&&c<a)
{
nian(c,19,b,a);
nian(c,19,a,b);
nian(a,19,b,c);
nian(c,20,b,a);
nian(c,20,a,b);
nian(a,20,b,c);
}
else if(c<b&&b<=a)
{
if(a==b)
{
nian(c,19,b,a);
nian(a,19,b,c);
nian(c,20,b,a);
nian(a,20,b,c);
return 0;
}
nian(c,19,b,a);
nian(c,19,a,b);
nian(a,19,b,c);
nian(c,20,b,a);
nian(c,20,a,b);
nian(a,20,b,c);
}
return 0;
}
y总版:按顺序枚举,没有了顺序的烦恼【妙啊】
#include <bits/stdc++.h>
using namespace std;
int days[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
bool check_valid(int year,int month,int day)
{
if(month==0||month>12)
return false;
if(day==0||month!=2&&day>days[month])
return false;
if(month==2)
{
int leap=year%100&&year%4==0||year%400==0;
if(day>28+leap)
return false;
}
return true;
}
int main()
{
int a,b,c;
scanf("%d/%d/%d",&a,&b,&c);//新写法,才知道
for(int date=19600101;date<=20591231;date++)
{
int year =date/10000,month=date%10000/100,day=date%100;
if(check_valid(year,month,day))
{
//判断当前数字是否是合法三种形式之一
if(year%100==a&&month==b&&day==c||
month==a&&day==b&&year%100==c||
day==a&&month==b&&year%100==c)
printf("%d-%02d-%02d\n",year,month,day);//不足两位自动补0
}
}
return 0;
}
7.1231. 航班时间
时差在往返飞的过程中被消掉了,最后推出的公式为两个相差时间的和/2,输入的处理十分新鲜(也没多新鲜,和昨天的差不多)
tips:①sscanf :从流中读入数据 ②…c_str():将string 类型转化成char[N]
#include <bits/stdc++.h>
using namespace std;
int get_second(int h,int m,int s)
{
return h*3600+m*60+s;
}
int get_time()
{
string line;
getline(cin,line);
if(line.back()!=')') line +="(+0)";//统一格式
int h1,m1,s1,h2,m2,s2,d;
sscanf(line.c_str(),"%d:%d:%d %d:%d:%d (+%d)",&h1,&m1,&s1,&h2,&m2,&s2,&d);
return get_second(h2,m2,s2)-get_second(h1,m1,s1)+d*24*3600;
}
int main()
{
int n;
scanf("%d",&n);
string line;
getline(cin,line);//吃回车
while(n--)
{
int time=(get_time()+get_time())/2;
int hour =time/3600,minute=time%3600/60,second=time%60;
printf("%02d:%02d:%02d\n",hour,minute,second);
}
return 0;
}
8.1241外卖店优先级
普通模拟会tle,所以有了批量处理两个订单区间
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
typedef pair<int,int >PII;
int n,m,T;
int score[N],last[N];
bool st[N];
PII order[N];
int main()
{
cin>>n>>m>>T;
for(int i=0; i<m; i++)
scanf("%d%d",&order[i].first,&order[i].second);
sort(order,order+m);//pair自带的排序
for(int i=0; i<m;)
{
//处理同一时刻同一店铺的订单数量
int j=i;
while(j<m&&order[j]==order[i])
j++;
int t=order[i].first,id=order[i].second,cnt=j-i;
i=j;
score[id]-=t-last[id]-1;
if(score[id]<0)
score[id]=0;
if(score[id]<=3)
st[id]=false;
score[id]+=cnt*2;
if(score[id]>5)
st[id]=true;
last[id]=t;
}
//处理最后订单时刻和t的关系
for(int i=1; i<=n; i++)
if(last[i]<T)
{
score[i]-=T-last[i];
if(score[i]<=3)
st[i]=false;
}
int res=0;
for(int i=1; i<=n; i++)
res+=st[i];
printf("%d\n",res);
return 0;
}
9.1238. 日志统计
计算区间同样需要优化处理【与上题对比】
#include <bits/stdc++.h>
#define x first
#define y second
using namespace std;
typedef pair<int ,int> PII;
const int N=100010;
int n,d,k;
PII logs[N];
int cnt[N];
bool st[N];
int main()
{
scanf("%d%d%d",&n,&d,&k);
for(int i=0;i<n;i++) scanf("%d%d",&logs[i].x,&logs[i].y);
sort(logs,logs+n);
for(int i=0,j=0;i<n;i++)
{
int id=logs[i].y;
cnt[id]++;
while(logs[i].x-logs[j].x>=d)
{
cnt[logs[j].y]--;//计算下一个区间
j++;
}
if(cnt[id]>=k) st[id]=true;
}
for(int i=0;i<=100000;i++)
if(st[i]) printf("%d\n",i);
return 0;
}