A:阅读理解。显然l的可能取值至多只有4n种,暴力枚举即可,对于确定的l答案显然为nk/gcd(nk,l)。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define int long long
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
int n,k,a,b;
signed main()
{
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
n=read(),k=read(),a=read(),b=read();
ll t=n*k;int s1=a+1,s2=k+1-a;int S1=b+1,S2=k+1-b;
ll mx=0,mn=t;
for (int i=0;i<=n;i++)
{
if (S1-s1+i*k<=n*k&&S1-s1+i*k>=0) mx=max(mx,t/gcd(t,S1-s1+i*k)),mn=min(mn,t/gcd(t,S1-s1+i*k));
if (S2-s1+i*k<=n*k&&S2-s1+i*k>=0) mx=max(mx,t/gcd(t,S2-s1+i*k)),mn=min(mn,t/gcd(t,S2-s1+i*k));
if (S1-s2+i*k<=n*k&&S1-s2+i*k>=0) mx=max(mx,t/gcd(t,S1-s2+i*k)),mn=min(mn,t/gcd(t,S1-s2+i*k));
if (S2-s2+i*k<=n*k&&S2-s2+i*k>=0) mx=max(mx,t/gcd(t,S2-s2+i*k)),mn=min(mn,t/gcd(t,S2-s2+i*k));
}
cout<<mn<<' '<<mx<<endl;
return 0;
//NOTICE LONG LONG!!!!!
}
B:对每个位置求出该位置上的数在排列中的下一个数在该位置后第一次出现的位置。以此倍增可以求出以每个位置为开头的合法子序列的最左右端点。查区间min即可。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 200010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
int n,m,q,a[N],b[N],p[N],pos[N],nxt[N][20],f[N][20],LG2[N];
int query(int l,int r)
{
return min(f[l][LG2[r-l+1]],f[r-(1<<LG2[r-l+1])+1][LG2[r-l+1]]);
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
n=read(),m=read(),q=read();
for (int i=1;i<=n;i++) a[i]=read(),p[a[i]]=i;
for (int i=1;i<=m;i++) b[i]=read();
nxt[m+1][0]=m+1;
for (int i=m;i>=1;i--)
{
nxt[i][0]=pos[a[p[b[i]]%n+1]];
if (!nxt[i][0]) nxt[i][0]=m+1;
pos[b[i]]=i;
}
for (int j=1;j<20;j++)
for (int i=1;i<=m+1;i++)
nxt[i][j]=nxt[nxt[i][j-1]][j-1];
for (int i=1;i<=m;i++)
{
f[i][0]=i;
for (int j=19;~j;j--)
if (n-1&(1<<j)) f[i][0]=nxt[f[i][0]][j];
}
for (int j=1;j<20;j++)
for (int i=1;i<=m;i++)
f[i][j]=min(f[i][j-1],f[min(m,i+(1<<j-1))][j-1]);
for (int i=2;i<=m;i++)
{
LG2[i]=LG2[i-1];
if ((2<<LG2[i])<=i) LG2[i]++;
}
for (int i=1;i<=q;i++)
{
int l=read(),r=read();
if (query(l,r)<=r) putchar('1');else putchar('0');
}
return 0;
//NOTICE LONG LONG!!!!!
}
C:y=x2+bx+c→y-x2=bx+c,发现就是一个直线的形式,要求的是有多少条直线其上方没有点,显然就是求上凸壳大小。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 100010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
int n,m,q[N],tail;
struct data
{
ll x,y;
bool operator <(const data&a) const
{
return x<a.x||x==a.x&&y>a.y;
}
data operator -(const data&a) const
{
return (data){x-a.x,y-a.y};
}
ll operator *(const data&a) const
{
return x*a.y-y*a.x;
}
}a[N],b[N];
signed main()
{
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
n=read();
for (int i=1;i<=n;i++) a[i].x=read(),a[i].y=read()-a[i].x*a[i].x;
sort(a+1,a+n+1);
for (int i=1;i<=n;i++)
{
int t=i;
while (a[t+1].x==a[i].x) t++;
b[++m]=a[i];i=t;
}
memcpy(a,b,sizeof(a));n=m;
q[1]=1;int tail=1;
for (int i=2;i<=n;i++)
{
while (tail>1&&(a[i]-a[q[tail-1]])*(a[q[tail]]-a[q[tail-1]])<=0) tail--;
q[++tail]=i;
}
cout<<tail-1;
return 0;
//NOTICE LONG LONG!!!!!
}
D、E:咕
小号打的。result:rank 62 rating +104