等比数列三角形
一、题目
二、解法
看到这道题,第一个想法就是暴枚 ,我们先考虑公比
k
k
k的范围。(规定边长递增)
据题,
a
+
a
k
>
a
k
2
a+ak>ak^2
a+ak>ak2
⇒
1
+
k
>
k
2
\Rightarrow 1+k>k^2
⇒1+k>k2
⇒
5
4
>
(
k
−
1
2
)
2
\Rightarrow \frac{5}{4}>(k-\frac{1}{2})^2
⇒45>(k−21)2
⇒
1
≤
k
<
5
+
1
2
\Rightarrow 1\leq k<\frac{\sqrt{5}+1}{2}
⇒1≤k<25+1
我们设
k
=
q
/
p
k=q/p
k=q/p(
p
,
q
p,q
p,q互质),所以首项必须要是
p
2
p^2
p2的倍数,可以得到
p
≤
n
p\leq \sqrt{n}
p≤n。我们枚举
q
q
q,可以得到所对应的
p
p
p的个数,然后考虑末项(因为要保证末项
≤
n
\leq n
≤n),时间复杂度
O
(
n
log
n
)
O(\sqrt{n}\log n)
O(nlogn)。
#include <cstdio>
#include <cmath>
#define int long long
const int MAXN = 1e6+5;
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,gg,ok[MAXN],p[MAXN],ans;
void init(int n)
{
for(int i=1;i<=n;i++)
{
gg=i*(2/(sqrt(5)+1));//算分子的最小值(开区间)
ok[i]=i-gg;//减去得到合法取值
}
for(int i=1;i<=n;i++)
{
for(int j=i<<1;j<=n;j+=i)
ok[j]-=ok[i];//要保证互质,用类似埃氏筛的方法
}
}
signed main()
{
init(1e6);
n=read();
for(int x=1;x*x<=n;x++)
ans+=(n/(x*x))*ok[x];//枚举末项,末项的取值乘上公比的取值(末项是q^2*一个数)
printf("%lld\n",ans);
}
一个简单的询问
一、题目
二、解法
如题所示,本题难度
NOI/NOI+/CTSC
\text{NOI/NOI+/CTSC}
NOI/NOI+/CTSC 。
看到区间问题,很有用的一个方向是差分,我们尝试对原问题进行一些变形:
x
[
l
1
,
r
1
]
×
x
[
l
2
,
r
2
]
=
(
x
[
1
,
r
1
]
−
x
[
1
,
l
1
−
1
]
)
×
(
x
[
1
,
r
2
]
−
x
[
1
,
l
2
−
1
]
)
=
x[l_1,r_1]\times x[l_2,r_2]=(x[1,r_1]-x[1,l_1-1])\times (x[1,r_2]-x[1,l_2-1])=
x[l1,r1]×x[l2,r2]=(x[1,r1]−x[1,l1−1])×(x[1,r2]−x[1,l2−1])=
x
[
1
,
r
1
]
×
x
[
1
,
r
2
]
+
x
[
1
,
l
1
−
1
]
×
x
[
1
,
l
2
−
1
]
−
x
[
1
,
l
2
−
1
]
×
x
[
1
,
r
1
]
−
x
[
1
,
l
1
−
1
]
×
x
[
1
,
r
2
]
x[1,r_1]\times x[1,r_2]+x[1,l_1-1]\times x[1,l_2-1]-x[1,l_2-1]\times x[1,r_1]- x[1,l_1-1]\times x[1,r_2]
x[1,r1]×x[1,r2]+x[1,l1−1]×x[1,l2−1]−x[1,l2−1]×x[1,r1]−x[1,l1−1]×x[1,r2]
发现它变成了四个独立的子问题,而这四个子问题都只有两个变量,莫队很容易写出来,就是维护一个和,时间复杂度
O
(
n
n
)
O(n\sqrt{n})
O(nn)。
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
const int MAXN = 50005;
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,m,k,q,l,r,a[MAXN],T[MAXN][2];
long long sum,ans[MAXN];
struct node
{
int l,r,id,ok;
bool operator < (const node &R) const
{
return l/m==R.l/m?r<R.r:l<R.l;
}
}s[MAXN*4];
void remove(int x,bool t)
{
T[a[x]][t]--;sum-=T[a[x]][t^1];
}
void add(int x,bool t)
{
T[a[x]][t]++;sum+=T[a[x]][t^1];
}
int main()
{
n=read();m=sqrt(n);
for(int i=1;i<=n;i++)
a[i]=read();
q=read();
for(int i=1;i<=q;i++)
{
int l1=read(),r1=read(),l2=read(),r2=read();
s[++k]=node{r1,r2,i,1};
s[++k]=node{l1-1,l2-1,i,1};
s[++k]=node{l1-1,r2,i,-1};
s[++k]=node{r1,l2-1,i,-1};
}
for(int i=1;i<=k;i++)
{
if(s[i].l<=s[i].r) continue;
swap(s[i].l,s[i].r);
}
sort(s+1,s+1+k);
for(int i=1;i<=k;i++)
{
int L=s[i].l,R=s[i].r;
while(l<L) remove(++l,0);
while(l>L) add(l--,0);
while(r>R) remove(r--,1);
while(r<R) add(++r,1);
ans[s[i].id]+=s[i].ok*sum;
}
for(int i=1;i<=q;i++)
printf("%lld\n",-ans[i]);
}
愤怒的小鸟
一、题目
二、解法
很容易想到装压,装压实现也很简单,不展开。
就讲一个点,考虑枚举两个猪的时候,只需要话费
O
(
n
)
O(n)
O(n),因为第一只猪是固定的,因为本题每只猪都要被打到,而且猪被打的顺序不重要,所以第一只猪就是状态中没有没打到的猪。
#include <cstdio>
#include <cstring>
#include <iostream>
#define eps 1e-6
using namespace std;
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int T,n,m,dp[1<<18];
double x[20],y[20];
bool chk(double x)
{
return x<eps && x>-eps;
}
int main()
{
T=read();
while(T--)
{
n=read();m=read();
m=1<<n;
for(int i=1;i<=n;i++)
scanf("%lf %lf",&x[i],&y[i]);
memset(dp,0x3f,sizeof dp);
dp[0]=0;
for(int i=0;i<m-1;i++)
{
for(int j=1;j<=n;j++)
{
if(!(i&(1<<j-1)))
dp[i|(1<<j-1)]=min(dp[i|(1<<j-1)],dp[i]+1);
}
int j=1;
for(;j<=n;j++)
if(!(i&(1<<j-1)))
break;
for(int k=1;k<=n;k++)
{
if(i&(1<<k-1) || x[j]==x[k]) continue;
double a=(y[j]*x[k]-y[k]*x[j])/(x[k]*x[j]*x[j]-x[j]*x[k]*x[k]);
double b=(y[j]-a*x[j]*x[j])/x[j];
if(a>=0) continue;
int to=i;
for(int l=1;l<=n;l++)
if(chk(a*x[l]*x[l]+b*x[l]-y[l]))
to|=(1<<l-1);
dp[to]=min(dp[to],dp[i]+1);
}
}
printf("%d\n",dp[m-1]);
}
}