1210. 连号区间数
二重循环枚举所有子区间,然后sort,然后判断是否符合条件(满足max-min=b-a),这个判断条件是要想清楚的
#include
#include
using namespace std;
const int N =10020,INF=100000000;
int n;
int a[N];
int main()
{
cin>>n;
for(int i=0;i<n;i++) cin>>a[i];
int res=0;
for(int i=0;i<n;i++)//枚举所有子区间,左端点
{
int maxv=-INF,minv=INF;//找每个区间的最大值最小值
for(int j=i;j<n;j++)//右端点
{
maxv=max(maxv,a[j]);
minv=min(minv,a[j]);
if(maxv-minv==j-i) res++;
}
}
cout<<res<<endl;
return 0;
}
1236. 递增三元组
1.暴力枚举三元组,判断是否满足条件,cnt++
2.枚举中间的B,找A中比bi小的个数,C中比bi大的个数,相乘=中间为bi时的方案数
如何找A中比bi小的…枚举?…用
前缀和
(1)cnt[i]表示在A中,i出现的次数; 一个for循环遍历A,cnt[A[i]]++;
(2)用cnt构造前缀和,s[i]=cnt[0]+cnt[1]+…cnt[i],表示在A中0~i出现的次数,s[b[i-1]],即在A中多少个数字小于bi
#include
#include
#include
#include
using namespace std;
typedef long long LL;
const int N=100010;
int n;
int a[N],b[N],c[N];
int as[N];//表示在A[]中有多少个数小于b[i]
int cs[N];//表示在C[]中有多少个数小于b[i]
int cnt[N],s[N];
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
for(int i=0;i<n;i++) scanf("%d",&b[i]);
for(int i=0;i<n;i++) scanf("%d",&c[i]);//变为从1开始
//求as[]
for(int i=0;i<n;i++) cnt[a[i]]++;//每一个a出现多少次
for(int i=1;i<N;i++) s[i]=s[i-1]+cnt[i];//求cnt前缀和
for(int i=0; i<n;i++) as[i]=s[b[i]];
memset(cnt,0,sizeof cnt);//清空cnt
memset(s,0,sizeof s);
for(int i=0;i<n;i++) cnt[c[i]]++;
for(int i=1;i<N;i++) s[i]=s[i-1]+cnt[i];//求cnt前缀和
for(int i=0; i<n;i++) cs[i]=s[N-1]-s[b[i]-1];
//枚举每个b[i]
LL res=0;
for(int i=0;i<n;i++) res+=(LL)as[i]*cs[i];
cout<<res<<endl;
return 0;
}
1245.特别数的和
就是一个数中只要含有2,0,1,9其中一个及以上,就符合条件,所以考虑怎么把数的每一位分离
1.把每一位数抠出来
int x=i;
while(x)
{
int t=x%10;
x/=10;
if( t == 2 || t == 0|| t==1 || t=9) res+=i;
}
2.把“2019”变成 2019
int x=0;
for(int i=0;i
#include
using namespace std;
int n;
int main()
{
cin>>n;
int res=0;
for(int i=1;i<=n;i++)
{
int x=i;
while(x)
{
int t=x%10;
x/=10;
if(t==2||t==0||t==1||t==9)
{
res+=i;
break;
}
}
}
cout<<res<<endl;
return 0;
}
1204. 错误票据
找断号、重号ID,首先想到是排序+遍历
1.此题输入无规律(ID个数不固定),故用字符串读
2.如何快速找到重号,断号ID
2.1将a[n]排序
2.2遍历a[n],若a[i]==a[i-1],发现重号ID
2.3若a[i]>=a[i-1]+2,发现断号ID
#include
#include
#include
#include
using namespace std;
const int N=10010;
int n;
int a[N];
int main()
{
int cnt;
cin>>cnt;
string line;
getline(cin,line);//忽略第一行回车
while(cnt--)
{
getline(cin,line);
stringstream ssin(line);//从line读入
while(ssin>>a[n]) n++;
}
sort(a,a+n);
int res1,res2;
for(int i=1;i<n;i++)
{
if(a[i]==a[i-1]) res1=a[i];
else if(a[i]>=a[i-1]+2) res2=a[i]-1;
}
cout<<res2<<' '<<res1<<endl;
return 0;
}
给定两个日期,求之间有多少是回文日期
1.枚举日期+判断是否回文,相当于手写日历
2.枚举回文串+判断是否合法日期
2.1枚举回文串(只枚举年份即可如2011)
2.2判断是否在所给日期范围内(直接当数值)
2.3判断日期是否合法
2.3.1 构造回文日期(比如枚举到2011----> 2011.11.02)
for(int j=0;j<4;j++) date=date*10+x%10,x/=10;//每次取最后一个数字加到后面
2.3.2 分离年月日
int year=date/10000;
int month=date%10000/100;
int day=date%100; 2.3.3 判断月份是否不对
2.3.4 判断月份对应的天数是否不对(非2月的情况下)
天数事先存好,只要索引即可 days[13]={0,31,28,31,30,31,30,31,31,30,31,30,31}
2.3.5 在2月的情况下判断是否闰年+判断天数
if(month==2)
{
int leap=year%100 && year%4 == 0 || year%400 ==0;
if(day>28 +leap ) return false;
} 2.3.6返回判断结果
#include
#include
#include
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;
}
1229. 日期问题
1.枚举日期
2.判断是否合法
3.判断是否是可能的表示
#include
#include
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||
year%100==c && month==a && day==b||
year%100==c && month==b && day==a)
printf("%d-%02d-%02d\n",year,month,day);//不足两位补0
}
}
return 0;
}
787. 归并排序
模板
1.确定分界点
2.递归地将左右排序
3.合二为一(归并)
3.1归并时用的是双指针思想
3.1.1有两个指针分别指向左右序列的头
3.1.2小的那个放到临时新序列,指针移动,大的不移动
merge_sort(q,l,mid),merge_sort(q,mid+1,r);
int k=0,i=l,j=mid+1;
while(i<=mid&&j<=r)
{
if(q[i]<=q[j]) tmp[k++]=q[i++];
else tmp[k++]=q[j++];
} 3.1.3直到有一个指针移到末尾了,将剩下数据全部填过来
while(i<=mid) tmp[k++]=q[i++];
while(j<=r) tmp[k++]=q[j++];
#include
using namespace std;
const int N =1000010;
int n;
int q[N],tmp[N];
void merge_sort(int q[],int l,int r)
{
if(l>=r) return ;
int mid=l+r>>1;
merge_sort(q,l,mid),merge_sort(q,mid+1,r);
int k=0,i=l,j=mid+1;
while(i<=mid&&j<=r)
{
if(q[i]<=q[j]) tmp[k++]=q[i++];
else tmp[k++]=q[j++];
}
while(i<=mid) tmp[k++]=q[i++];
while(j<=r) tmp[k++]=q[j++];
for(int i=l,j=0;i<=r;i++,j++) q[i]=tmp[j];
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&q[i]);
merge_sort(q,0,n-1);
for(int i=0;i<n;i++) printf("%d ",q[i]);
return 0;
}
1219. 移动距离
蛇形矩阵,求任意两点曼哈顿距离|x1-x2|+|y1-y2|
1 2 3 4 5 6
12 11 10 9 8 7
13 14 15 16 17 18
关键,给出一个点的数值,得到它的坐标
行号=n/宽度 下取整
非蛇形矩阵 列号=n%宽度
列号=奇数行(即n/宽度为奇数)要反转
#include
#include
#include
using namespace std;
int main()
{
int w,m,n;
scanf("%d%d%d",&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;
}
1241. 外卖店优先级
如何模拟这个过程?
1.暴力:枚举每个时刻的所有情况
1.1判断哪些店有订单,哪些无订单
1.2有订单的店score+=2*订单
1.3无订单score–(若优先级为0,则不变)
1.4若score>5 st[id]=true; 若score<=3 st[id]=false//移出优先缓存
1.5遍历所有店铺 res+=st[i],留下的都是此时刻内在优先缓存的
2.将无订单的店的score–,先不处理,直到下次它有订单的时候一起处理
2.0 score[i]表示第i个店铺当前优先级;last[i]表示第i个店铺上一次有订单的时刻;st[i]表示第i个店铺当前是否处于优先缓存
2.1将所有订单按照时间排序
2.2对于每个订单,每次处理一批订单
2.2.1 score[id]-=t-last[id]-1;