由题意是在 1∼N 的某个排列中有多少个连号区间,所以每个数出现并且不重复!
如果是连续的,那么Max-Min==j-i([i,j])
#include
#include
using namespace std;
const int N=10010,INF = 100000000;
int a[N];
int main()
{
int n;
cin>>n;
int count=0;
for(int i=0;i>a[i];
for(int i=0;i
由题意可知,需要从A、B、C数组中各取一个,使得A
排序+二分:先对A、C数组进行排序然后用二分求出A中小于B的第一个个数的位置和C中大于B的第一个位置。
前缀和:
排序+二分:
#include
#include
using namespace std;
const int N=100010;
typedef long long LL;
int a[N],b[N],c[N];
int main()
{
int n;
cin>>n;
for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);
for (int i = 1; i <= n; i ++ ) scanf("%d", &b[i]);
for (int i = 1; i <= n; i ++ ) scanf("%d", &c[i]);
sort(a+1,a+n+1);
sort(c+1,c+n+1);
LL res=0;
for(int i=1;i<=n;i++)
{
int l=1,r=n;
while(lb[i]) r=mid;
else l=mid+1;
}
if(c[r]>b[i]) res+=(LL)(temp)*(LL)(n-l+1);
}
}
cout<
前缀和:
3个数组的所有数都加1,是因为在不影响数与数之间的大小关系下,让该行代码s[b[i] - 1];
避免出现b[i]为0的情况导致空指针异常
#include
#include
using namespace std;
const int N=100010;
typedef long long LL;
int a[N],b[N],c[N],s[N],t[N],x[N],y[N];
int main()
{
int n;
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]++;
LL res=0;
for(int i=1;i<=n;i++)
{
s[a[i]]++;
t[c[i]]++;
}
for(int i=1;i<=N;i++)
{
x[i]=x[i-1]+s[i];
y[i]=y[i-1]+t[i];
}
for(int i=1;i<=n;i++)
{
res+=(LL)(x[b[i]-1])*(LL)(y[N]-y[b[i]]);
}
cout<
每次取出个位数判断是否满足要求即可!
字符型数组转化成整型:
int x=0;
for(int i=0;i
{
x=x*10+s[i]-'0';
}
#include
using namespace std;
int main()
{
int n;
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==1||t==2||t==0||t==9) {
res+=i;
break;//只要存在指定数字结束本次循环
}
}
}
cout<
先对数组进行排序操作,然后遍历如果存在前一个和后一个相等则为重号ID,如果存在当a[i]>=a[i-1]+2,则两者之前存在缺失ID即a[i]-1。
#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);
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]) res2 = a[i]; // 重号
else if (a[i] >= a[i - 1] + 2) res1 = a[i] - 1; // 断号
cout << res1 << ' ' << res2 << endl;
return 0;
}
还可以使用以下代码对数组进行读入:
int x, i = 0;
cin >> x;//过滤
while(cin >> x) a[i++] = x;
①枚举回文数(年份的范围是在1000~10000)
先枚举前四位,然后算出八位数的日期
int res=0;
for(int i=1000;i<10000;i++)
{
int r=i,x=i;
//形成八位数的日期
for(int i=0;i<4;i++) r=r*10+x%10,x/=10;
if(r>=date1&&r<=date2&&check(r)) res++;
}
②判断是否在范围内
③判断日期是否合法
先开一个每个月份天数的集合,先判断月份(除二月之外)、天数是否满足,然后根据平年闰年对二月的天数进行讨论(平年-28天 闰年-29天)
bool check(int data)
{
int year=data/10000;
int month=data%10000/100;
int day=data%100;
if(!month||month>12||!day) return false;
if(month!=2&&day>days[month]) return false;
if(month==2)
{
bool flag=year%100&&year%4==0||year%400==0;
if(day>28+flag)//如果是闰年则二月是29天需要+100
return false;
}
return true;
}
#include
#include
using namespace std;
int days[13]={0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
bool check(int data)
{
int year=data/10000;
int month=data%10000/100;
int day=data%100;
if(!month||month>12||!day) return false;
if(month!=2&&day>days[month]) return false;
if(month==2)
{
bool flag=year%100&&year%4==0||year%400==0;
if(day>28+flag)//如果是闰年则二月是29天需要+100
return false;
}
return true;
}
int main()
{
int date1,date2;
cin>>date1>>date2;
int res=0;
for(int i=1000;i<10000;i++)
{
int r=i,x=i;
//形成八位数的日期
for(int i=0;i<4;i++) r=r*10+x%10,x/=10;
if(r>=date1&&r<=date2&&check(r)) res++;
}
cout<
在上一题的基础上加上对回文日期的判断(双指针方法)和AB型日期的特判
#include
#include
using namespace std;
int days[13]={0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
bool check(int data)
{
int year=data/10000;
int month=data%10000/100;
int day=data%100;
if(!month||month>12||!day) return false;
if(month!=2&&day>days[month]) return false;
if(month==2)
{
bool flag=year%100&&year%4==0||year%400==0;
if(day>28+flag)//如果是闰年则二月是29天需要+100
return false;
}
return true;
}
bool check1(string data)
{
int l=data.length();
for(int i=0,j=l-1;i>date1;
int res1=0,res2=0;
for(int i=date1+1;i<=99999999;i++)
{
if(check(i))
{
string s=to_string(i);
if(check1(s)&&!flage)//回文判断
{
res1=i;
flage=1;
}
if(check2(s))//回文特判
{
res2=i;
break;
}
}
}
cout<
①确定分界点 mid=(l+r)>>1
②递归排序left、right
③归并----合二为一
#include
using namespace std;
const int N=100010;
int q[N],temp[N];
void merge_sort(int q[],int l,int r)
{
while(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]) temp[k++]=q[i++];
else temp[k++]=q[j++];
}
while(i<=mid) temp[k++]=q[i++];
while(j<=r) temp[k++]=q[j++];
for(int i=l,j=0;i<=r;i++,j++) q[i]=temp[j];
}
int main()
{
int n;
cin>>n;
for(int i=0;i>q[i];
merge_sort(q,0,n-1);
for(int i=0;i
在归并排序的归并这一步骤中添加一个计数的操作,res+=mid-i+1在左半段有大于右半段这种情况下满足逆序对存在的条件,则左半段后面部分也同样大于右半段此时的值。
while(i<=mid&&j<=r)
{
if(q[i]<=q[j]) temp[k++]=q[i++];
else
{
temp[k++]=q[j++];
res+=mid-i+1;
}
}
#include
using namespace std;
const int N=100010;
int q[N],temp[N];
long long res;
void merge_sort(int q[],int l,int r)
{
while(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]) temp[k++]=q[i++];
else
{
temp[k++]=q[j++];
res+=mid-i+1;
}
}
while(i<=mid) temp[k++]=q[i++];
while(j<=r) temp[k++]=q[j++];
for(int i=l,j=0;i<=r;i++,j++) q[i]=temp[j];
}
int main()
{
int n;
cin>>n;
for(int i=0;i>q[i];
merge_sort(q,0,n-1);
cout<
由二维数组的值来计算该数所在的行列数,这里便于好运算我们从0开始(所有数都减一),w为一行多少个数,x为该数的值,行号:x/w 列号:x%w(奇数行需要反转,w-1-x%w)
曼哈顿距离:
欧几里得距离:
#include
#include
#include
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;
}
我们将日期看作八位数的数字,从19600101到20591231枚举,然后检验一下日期是否合法,再分三种情况输出日期的组成(年/月/日、月/日/年、日/月/年)
这里最好用scanf和printf进行格式化输入输出
scanf("%d/%d/%d",&a,&b,&c);
printf("%d-%02d-%02d\n", year, month, day);(02代表不足两位用0补齐)
#include
#include
using namespace std;
int days[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
bool check(int year,int month,int day)
{
if(month==0||month>12) return false;
if(day==0) return false;
if(month!=2)
{
if(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 i=19600101;i<=20591231;i++)
{
int year=i/10000,month=i%10000/100,day=i%100;
if(check(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);
}
}
return 0;
}
①分析题意:
往东飞 : 到达时间 - (起飞时间 - 时差)= 到达时间1 - 起飞时间1 + 时差
往西飞: 到达时间 - (起飞时间 + 时差)= 到达时间2 - 起飞时间2 - 时差
两次时间相加 = 到达时间1 - 起飞时间1 + 到达时间2 - 起飞时间2
所以一次飞行时间为: 两次的时间差 / 2②具体思路:
我们将时间化成秒来计算,使用getline读取一行,然后判断后面是否有(+1)这种情况,统一格式如果没有加"(+0)",再用sscanf(a,b,c)。
line.c_str():把string 对象转换成c中的字符串样式
line.back():返回字符串最后一个字符
sscanf(a,b,c):是把a中的每个字符,按照b格式,赋值给c
#include
#include
#include
#include
using namespace std;
int get_seconds(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_seconds(h2,m2,s2)-get_seconds(h1,m1,s1)+24*60*60*d;
}
int main()
{
int n;
scanf("%d\n",&n);//忽略掉第一行的回车
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;
}
因为店铺订单呈离散化,所以我们压缩,直接算这次订单和上次订单两者之前相差的时间。
优秀题解:AcWing 1241. 外卖店优先级 - AcWing
#include
#include
#include
#include
#define x first
#define y second
using namespace std;
typedef pair PII;
const int N = 100010;
int n, m, T;
//分别表示第i个店铺当前的优先级、表示第i个店铺上一次有订单的时刻
int score[N], last[N];
//表示第i个店铺当前是否处于优先缓存中
bool st[N];
PII order[N];
int main()
{
scanf("%d%d%d",&n,&m,&T);
for(int i=0;i5) st[id]=true;
last[id]=t;
}
for(int i=1;i<=n;i++)
if(last[i]