code+7正式赛划水记+HardA~C题解
被同年级的吊锤了
划水
sometimes naive
2:00看题,感觉不是很可做
20分的时候有人切了T2,看了一下发现是sb题,20min切掉
T1写了暴力找规律无果,交了10分上去
去看T3,发现白给40分直接写
150分以为稳了,还有1h的时候搞T1
想到从后往前构造(?),因为决策点并不多并且主要时间在二分上所以是正解(暴论)
打出了65,稍微调一下变成93
这时还剩30min,大概是30多名
然后看着排名飞速往后掉慌得一笔,去搞T3p质数的部分分搞不出来(并没有发现与模4有关)
最后10min开始卡T1,45名
最后5min掉出50名
最后3min想到缩二分上下界,52名
最后1min一Fa♂入魂,咸鱼翻身√
A
https://next.xuetangx.com/live/live20200523it002/live20200523it002/4071197/5468641
k<=10^12
题解是从前往后做的,设i以及i之后的操作次数为x,则最后一次一定是i,并且从后往前每i+1次中有一次i
那么i被操作的次数为ceil(x/(i+1)),a则要加上第一次i前面的那一段,即a[i]=i-(x-1)%(i+1)
然后把x剪掉ceil(x/(i+1)),往后做即可
二分n,然后奇妙卡上下界
也可以从后往前做,那就会遇到要决策0或i的地方,因为决策点不多所以可以过
#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define ll long long
#define file
using namespace std;
int i,j,k,l,r,mid,n,len,ss;
ll a[10000001],K,s,sum;
char st[20000001];
ll pd(int n,ll s,ll sum,bool tp)
{
int i,j,k,l,ss;
fd(i,n,1)
{
ss=s%i;
if (!(ss)) {if (!tp) a[i]=0; else a[i]=i;}
else
a[i]=i-ss;
s+=(a[i]+s)/i;sum+=a[i];
}
return sum;
}
void Write(int t)
{
char a[10];
int i=0;
if (!t) {st[++len]='0';st[++len]=' ';return;}
while (t) a[++i]=t%10,t/=10;
while (i) st[++len]=a[i--]+'0';
st[++len]=' ';
}
int main()
{
#ifdef file
freopen("a.in","r",stdin);
#endif
freopen("a.out","w",stdout);
scanf("%lld",&K);
l=1;r=2000000;
if (K>100000000000ll)
l=floor(sqrt(K)*1.77244),r=floor(sqrt(K)*1.77255);
while (l<r)
{
mid=(l+r)/2;a[mid]=mid;
if (pd(mid-1,1,0,1)<K)
l=mid+1;
else
r=mid;
}
n=l;a[n]=n;s=1;sum=n;
fd(i,n-1,1)
{
ss=s%i;
if (!(ss))
{
if (pd(i-1,s+s/i,sum-n,1)>=K)
a[i]=0;
else
a[i]=i;
}
else
a[i]=i-ss;
s+=(a[i]+s)/i;sum+=a[i];
}
len=-1;
Write(n);st[++len]='\n';
fo(i,1,n) Write(a[i]);st[++len]='\n';
fwrite(st,1,len,stdout);
fclose(stdin);
fclose(stdout);
return 0;
}
B
直接求询问i的答案,把更新i所要的区间[ki+1,(k+1)i]挂在线段树上,如果操作1经过了区间就更新i的答案
简单题
#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(a,b) (a<b?a:b)
#define low(x) ((x)&-(x))
#define ll long long
//#define file
using namespace std;
int b[100001],n,Q,i,j,k,l,tp,x,y,z;
vector<int> tr[400001];
ll Tr[100001],Tr2[100001];
void Change(int t)
{
while (t<=n) {++Tr[t]; t+=low(t);}
}
ll Find(int t)
{
ll ans=0; while (t) {ans+=Tr[t];t-=low(t);};return ans;
}
void Change2(int t)
{
while (t<=n) {++Tr2[t]; t+=low(t);}
}
ll Find2(int t)
{
ll ans=0; while (t) {ans+=Tr2[t];t-=low(t);};return ans;
}
void change(int t,int l,int r,int x,int y,int s)
{
int mid=(l+r)/2;
if (x>y) return;
if (x<=l && r<=y) {tr[t].push_back(s);return;}
if (x<=mid) change(t*2,l,mid,x,y,s);
if (mid<y) change(t*2+1,mid+1,r,x,y,s);
}
void find(int t,int l,int r,int x)
{
int mid=(l+r)/2,tot=tr[t].size(),i,s;
if (tot)
{
fo(i,0,tot-1)
{
s=tr[t][i];
if (((l-1)/s)<b[s]) continue;
Change(s);++b[s];
while (b[s]*s<=n && Find2(min((b[s]+1)*s,n))-Find2(b[s]*s)) ++b[s],Change(s);
change(1,1,n,b[s]*s+1,min((b[s]+1)*s,n),s);
}
tr[t].clear();
}
if (l==r) return;
if (x<=mid) find(t*2,l,mid,x);
else
find(t*2+1,mid+1,r,x);
}
int main()
{
#ifdef file
freopen("b.in","r",stdin);
#endif
scanf("%d%d",&n,&Q);
fo(i,1,n) change(1,1,n,1,i,i);
for (;Q;--Q)
{
scanf("%d",&tp);
if (tp==1)
{
scanf("%d",&x);
Change2(x);
find(1,1,n,x);
}
else
{
scanf("%d%d",&x,&y);
printf("%lld\n",(Find(y)-Find(x-1))+(y-x+1));
}
}
fclose(stdin);
fclose(stdout);
return 0;
}
C
n<=10^5,p<=10^7
40分直接枚举一个丢到桶里,然后把枚举另一个计算
p是质数的时候答案长这样
因为p没有平方因子,所以把p分解成Πpi后直接crt
即求a^2+b^2=x%p等价于求a^2+b^2=x%pi方程组的解
然后可以求出每个的解乘起来
#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define ll long long
//#define file
using namespace std;
int p[3163],T,n,i,j,k,l,P,x,len;
bool f[3163];
ll ans;
void init()
{
int i,j,k,l;
fo(i,2,3162)
{
if (!f[i]) p[++len]=i;
fo(j,1,len)
if (i*p[j]<=3162)
{
f[i*p[j]]=1;
if (!(i%p[j])) break;
}
else
break;
}
}
int js(int p)
{
if (p%4==1) {if (!(x%p)) return p*2-1;return p-1;}
if (p%4==3) {if (!(x%p)) return 1;return p+1;}
}
int main()
{
#ifdef file
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
#endif
init();
scanf("%d",&T);
for (;T;--T)
{
scanf("%d%d",&P,&x);ans=1;
fo(i,1,len)
if (!(P%p[i]))
P/=p[i],ans*=js(p[i]);
if (P>1) ans*=js(P);
printf("%lld\n",ans);
}
fclose(stdin);
fclose(stdout);
return 0;
}