A. The beautiful values of the palace
B. super_log
题意:求解
a
a
…
a
a^{a^{\dots^a}}
aa…a % m的值
思路:m等于1的时候,返回
x
%
m
+
m
x\%m+m
x%m+m,即返回1。递归出口返回1还是0,取决于后面的操作,如果后面还有判断的操作,就返回x%m,否则就返回x%m+m
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <cstring>
#include <string>
#include <cmath>
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b) memset(a,b,sizeof(a))
#define mp make_pair
#define ll long long
#define pb push_back
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ls (rt<<1)
#define rs ((rt<<1)|1)
#define isZero(d) (abs(d) < 1e-8)
using namespace std;
const int maxn=1e5+5,INF=0x3f3f3f3f;
const int mod=1e9+7;
ll euler(ll n)
{
ll ret=n,a=n;
for(ll i=2;i*i<=a;++i)
{
if(a%i==0)
{
ret=ret/i*(i-1);
while(a%i==0)
a/=i;
}
}
if(a>1)
ret=ret/a*(a-1);
return ret;
}
ll mm(ll x,ll m)
{
return x<m?x:x%m+m;
}
ll QuickPower(ll base,ll n,ll mod)
{
ll ret=1;
while(n)
{
if(n&1)
ret=mm(ret*base,mod);
n>>=1;
base=mm(base*base,mod);
}
return ret;
}
ll recursion(ll a,ll b,ll m)
{
if(m==1)
return 1;
if(b==0)
return 1;
ll exp=recursion(a,b-1,euler(m));
return QuickPower(a,exp,m);
}
int main()
{
int t;
cin>>t;
while(t--)
{
ll a,b,m;
cin>>a>>b>>m;
if(a==1||b==0)
{
cout<<1%m<<"\n";
continue;
}
cout<<recursion(a,b,m)%m<<"\n";
}
return 0;
}
C. Tsy’s number 5
D. Robots
E. K Sum
F. Greedy Sequence
题意:对于每个 i,它的下标是 p o s [ i ] pos[i] pos[i],找 [ p o s [ i ] − k , p o s [ i ] + k ] [pos[i]-k,pos[i]+k] [pos[i]−k,pos[i]+k]中小于i的数 x ,答案就是 a n s [ i ] = a n s [ x ] + 1 ans[i]=ans[x]+1 ans[i]=ans[x]+1
方法一:滑动窗口搜出每个i左边小于i的最大值,和右边小于i的最大值。最后从小到大遍历这些数,取左右两边的最大值,更新答案
方法二:线段树维护最大值,每次加点前,先查询然后在加点
方法三:主席树查询小于k的最大值,就是查询主席树上k点左边一位的值
代码1:滑动窗口+二分
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <cstring>
#include <string>
#include <cmath>
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b) memset(a,b,sizeof(a))
#define mp make_pair
#define ll long long
#define pb push_back
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ls (rt<<1)
#define rs ((rt<<1)|1)
#define isZero(d) (abs(d) < 1e-8)
using namespace std;
const int maxn=1e5+5,INF=0x3f3f3f3f;
const int mod=1e9+7;
int t,n,k,a[maxn],pos[maxn],l[maxn],r[maxn];
int ans[maxn];
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d %d",&n,&k);
rep(i,1,n)
{
scanf("%d",&a[i]);
l[i]=r[i]=0;
pos[a[i]]=i;
}
set<int> s;
for(int i=1;i<=n;++i)
{
s.insert(a[i]);
if(i-k-1>=1)
s.erase(a[i-k-1]);
auto it=s.lower_bound(a[i]);
if(it!=s.begin())
l[a[i]]=*(--it);
}
s.clear();
for(int i=n;i>=1;--i)
{
s.insert(a[i]);
if(i+k+1<=n)
s.erase(a[i+k+1]);
auto it=s.lower_bound(a[i]);
if(it!=s.begin())
r[a[i]]=*(--it);
}
for(int i=1;i<=n;++i)
{
int x=max(l[i],r[i]);
ans[i]=ans[x]+1;
printf("%d%c",ans[i],i==n?'\n':' ');
}
}
return 0;
}
代码2:线段树维护区间最大值
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <cstring>
#include <string>
#include <cmath>
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b) memset(a,b,sizeof(a))
#define mp make_pair
#define ll long long
#define pb push_back
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ls (rt<<1)
#define rs ((rt<<1)|1)
#define isZero(d) (abs(d) < 1e-8)
using namespace std;
const int maxn=1e5+5,INF=0x3f3f3f3f;
int n,k,t,ST[maxn<<2];
int a[maxn],pos[maxn],ans[maxn];
void Push_up(int rt)
{
ST[rt]=max(ST[ls],ST[rs]);
}
void Build(int rt,int L,int R)
{
ST[rt]=0;
if(L==R)
return;
int mid=(L+R)>>1;
Build(ls,L,mid);
Build(rs,mid+1,R);
}
void Update(int rt,int p,int L,int R,int c)
{
if(L==R)
{
ST[rt]=c;
return ;
}
int mid=(L+R)>>1;
if(p<=mid)
Update(ls,p,L,mid,c);
if(p>mid)
Update(rs,p,mid+1,R,c);
Push_up(rt);
}
int Query(int rt,int l,int r,int L,int R)
{
if(l<=L&&R<=r)
return ST[rt];
int mid=(L+R)>>1;
int ans=0;
if(l<=mid)
ans=max(ans,Query(ls,l,r,L,mid));
if(r>mid)
ans=max(ans,Query(rs,l,r,mid+1,R));
return ans;
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d %d",&n,&k);
rep(i,1,n)
{
scanf("%d",&a[i]);
pos[a[i]]=i;
}
Build(1,1,n);
for(int i=1;i<=n;++i)
{
int l=max(1,pos[i]-k);
int r=min(n,pos[i]+k);
int x=Query(1,l,r,1,n);
ans[i]=ans[x]+1;
Update(1,pos[i],1,n,i);
}
rep(i,1,n)
printf("%d%c",ans[i],i==n?'\n':' ');
}
return 0;
}
代码3:主席树求小于k的最大值:就是求在叶节点k,左边一位的下标
查询思路:我们找的是:主席树位置p左边第一个有值的数
我们肯定是按照:左右两个区间去讨论怎么取, 如果在p<=mid+1,那么我们要找的肯定是在左区间。直接返回就好了。如果p>mid+1,那么可能在左右两个区间,优先找右区间,找不到再找左区间
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <cstring>
#include <string>
#include <cmath>
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b) memset(a,b,sizeof(a))
#define mp make_pair
#define ll long long
#define pb push_back
#define pii pair<int,int>
#define pll pair<ll,ll>
#define isZero(d) (abs(d) < 1e-8)
using namespace std;
const int maxn=1e5+5,INF=0x3f3f3f3f;
const int mod=1e9+7;
int t,n,k,a[maxn],pos[maxn],version[maxn],ans[maxn];
int no,ST[maxn*40],ls[maxn*40],rs[maxn*40];
int Build(int L,int R)
{
int rt=++no;
ST[rt]=ls[rt]=rs[rt]=0;
if(L==R)
return rt;
int mid=(L+R)>>1;
ls[rt]=Build(L,mid);
rs[rt]=Build(mid+1,R);
return rt;
}
int Update(int pre,int p,int L,int R)
{
int rt=++no;
ls[rt]=ls[pre];
rs[rt]=rs[pre];
ST[rt]=ST[pre]+1;
if(L==R)
return rt;
int mid=(L+R)>>1;
if(p<=mid)
ls[rt]=Update(ls[pre],p,L,mid);
if(p>mid)
rs[rt]=Update(rs[pre],p,mid+1,R);
return rt;
}
//我们找的是:主席树位置p左边第一个有值的数
//我们肯定是按照:左右两个区间去讨论怎么取,
//如果在p<=mid+1,那么我们要找的肯定是在左区间。直接返回就好了
//如果p>mid+1,那么可能在左右两个区间,优先找右区间,找不到再找左区间
int Query(int pre,int now,int k,int L,int R)
{
if(ST[now]-ST[pre]==0)
return -1;
if(L==R)
return L<k?L:-1;
int mid=(L+R)>>1;
if(k<=mid+1||ST[rs[now]]-ST[rs[pre]]==0)
return Query(ls[pre],ls[now],k,L,mid);
int tmp=Query(rs[pre],rs[now],k,mid+1,R);
if(tmp!=-1)
return tmp;
return Query(ls[pre],ls[now],k,L,mid);
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d %d",&n,&k);
rep(i,1,n)
{
scanf("%d",&a[i]);
pos[a[i]]=i;
}
no=0;
version[0]=Build(1,n);
for(int i=1;i<=n;++i)
version[i]=Update(version[i-1],a[i],1,n);
//从小到大遍历这n个数,所以位置就是1~n
for(int i=1;i<=n;++i)
{
int L=max(1,pos[i]-k);
int R=min(n,pos[i]+k);
int x=Query(version[L-1],version[R],i,1,n);
ans[i]=ans[x]+1;
}
rep(i,1,n)
printf("%d%c",ans[i],i==n?'\n':' ');
}
return 0;
}
G. Quadrilateral
#include <iostream>
#include <algorithm>
#include <cstdio>
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define ll long long
using namespace std;
int T,x[10];
ll f(ll n)
{
return (1+n)*n/2;
}
ll f2(ll n)
{
return n*(n+1)*(n+2)/6;
}
ll cal(ll a,ll b,ll c)
{
if(a<1||b<1||c<2)
return 0;
a=min(a,c-1);
b=min(b,c-1);
if(a+b<=c)
return (f(c-1)-f(c-b-1)+f(c-a)-f(c-a-b))*a/2;
else
return (f(c-1)-f(c-b-1)+f(b))*(c-b)/2+f2(b-1)-f2(c-a-1);
}
ll solve(ll a,ll b,ll c,ll d)
{
if(a<1||b<1||c<1||d<1)
return 0;
ll ret=1ll*a*b*c;
ret-=cal(b,c,d-1)-cal(b,c,d-a-1);
ret-=cal(a,b,c-d);
ret-=cal(a,c,b-d);
ret-=cal(b,c,a-d);
return ret;
}
int main()
{
scanf("%d",&T);
while(T--)
{
rep(i,1,8)
scanf("%d",&x[i]);
ll ans=0;
for(int i=x[7];i<=x[8];++i)
{
ans+=solve(x[2],x[4],x[6],i)-solve(x[1]-1,x[4],x[6],i)-solve(x[2],x[3]-1,x[6],i)
-solve(x[2],x[4],x[5]-1,i)+solve(x[1]-1,x[3]-1,x[6],i)+solve(x[1]-1,x[4],x[5]-1,i)
+solve(x[2],x[3]-1,x[5]-1,i)-solve(x[1]-1,x[3]-1,x[5]-1,i);
}
printf("%lld\n",ans);
}
return 0;
}