长沙集训Ⅱ——Day5
T1
嘟嘟噜
经典的约瑟夫问题,但需要比较低的时间复杂度。
看到数据范围,知道这题肯定不能用模拟(
优化1
先把每个人的编号当成
我们来拿
显然,时间复杂度已经被优化到
优化2
这个方法的时间复杂度约为
#include<cstdio>
#include<cstring>
using namespace std;
int T;
long long n,m;
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%lld%lld",&n,&m);
long long f1=0,f2,x,i=2;
if(m==1)
{
printf("%lld\n",n);
continue;
}
while(i<=n)
{
if(f1+m<i)
{
x=(i-f1)/m;
if(i+x<n)
{
i+=x;
f2=f1+x*m;
f1=f2;
}
else
{
f2=f1+m*(n-i);
i=n;
f1=f2;
}
}
f2=(f1+m)%i;
f1=f2;
i++;
}
printf("%lld\n",f2+1);
}
return 0;
}
T2
这题简直就是数学题。。。
首先,要知道下面这个结论——
如果\vec a=(x_{1},y_{1}) ,\vec b=(x_{2},y_{2}) ,那么,|\vec a×\vec b|=|x_{1}y_{2}-x_{2}y_{1}| 。
再来看一下题目中的式子。
然后我们只要用树状数组维护这三个前缀和即可。
注:1.每次修改不仅要修改树状数组中的数,还要修改原序列中的数
#include<cstdio>
using namespace std;
const long long MN=1000010,p=20170927;
long long n,m,x[MN],y[MN],a[MN],b[MN],c[MN];
inline long long lowbit(long long x) { return x&(-x); }
inline void add(long long x,long long y,long long g[])
{
for(;x<=n;x+=lowbit(x)) g[x]=(g[x]+y)%p;
}
inline long long ask(long long x,long long g[])
{
long long res=0;
for(;x;x-=lowbit(x)) res=(res+g[x])%p;
return res;
}
int main()
{
scanf("%lld%lld",&n,&m);
for(long long i=1;i<=n;i++)
{
scanf("%lld%lld",&x[i],&y[i]);
add(i,x[i]*x[i],a);
add(i,y[i]*y[i],b);
add(i,x[i]*y[i],c);
}
for(long long i=1;i<=m;i++)
{
long long h;
scanf("%lld",&h);
if(h==1)
{
long long pp,xx,yy;
scanf("%lld%lld%lld",&pp,&xx,&yy);
add(pp,((p+xx*xx-x[pp]*x[pp])%p+p)%p,a);
add(pp,((p+yy*yy-y[pp]*y[pp])%p+p)%p,b);
add(pp,((p+xx*yy-x[pp]*y[pp])%p+p)%p,c);
x[pp]=xx; y[pp]=yy;
}
else
{
long long l,r;
scanf("%lld%lld",&l,&r);
long long aa=(p+ask(r,a)-ask(l-1,a))%p,
bb=(p+ask(r,b)-ask(l-1,b))%p,
cc=(p+((p+ask(r,c)-ask(l-1,c))%p)*((p+ask(r,c)-ask(l-1,c))%p)%p)%p;
printf("%lld\n",(p+(aa%p)*(bb%p)%p-cc%p)%p);
}
}
return 0;
}
T3
凤凰院凶真
本题很明显是让我们求最长公共上升子序列(
所以我们只要解决如何保存状态的问题就行了(详见代码)。
#include<cstdio>
#include<vector>
#include<iostream>
using namespace std;
int n,m,a[5010],b[5010],dp[5010][5010],pre[5010][5010],pos,ans;
vector<int>res;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
scanf("%d",&m);
for(int i=1;i<=m;i++) scanf("%d",&b[i]);
a[0]=-0x3f3f3f3f; b[0]=-0x3f3f3f3f;
int tmp=0,id=0;
for(int i=1;i<=n;i++)
{
tmp=0,id=0;
for(int j=1;j<=m;j++)
{
if(a[i]==b[j]) dp[i][j]=tmp+1,pre[i][j]=id;
else dp[i][j]=dp[i-1][j];
if(b[j]<a[i]&&tmp<dp[i-1][j]) tmp=dp[i-1][j],id=j;
}
}
for(int i=1;i<=m;i++)
if(ans<=dp[n][i]) ans=dp[n][i],pos=i;
printf("%d\n",ans);
if(!ans) return 0;
res.push_back(pos);
while(n&&pos)
{
if(pre[n][pos])
{
pos=pre[n][pos];
res.push_back(pos);
}
else
n--;
}
for(int i=res.size()-1;i>=0;i--)
printf("%d ",b[res[i]]);
return 0;
}