The Preliminary Contest for ICPC Asia Nanjing 2019

A. The beautiful values of the palace

B. super_log

题意:求解 a a … a a^{a^{\dots^a}} aaa % 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;
}

H. Holy Grail

I. Washing clothes

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Sure, I'd be happy to give you some ideas for organizing a speech contest. Here are some suggestions: 1. Determine the theme and rules: Decide on the theme of the contest and the rules for participants. Will it be an open topic, or will there be a specific theme? What is the maximum length of the speech? Will there be any specific guidelines for language or content? 2. Decide on the judging criteria: Determine how the speeches will be evaluated. Will judges be looking for content, delivery, or both? Will there be a score sheet or rubric that judges will use to score the speeches? 3. Recruit judges: Find people who are qualified to judge the speeches. Ideally, they should have experience in public speaking or have a background in the theme of the contest. 4. Promote the contest: Advertise the contest to potential participants, such as students, professionals, or members of a specific community. Use social media, flyers, and other methods to get the word out. 5. Registration and selection: Set a deadline for registration and selection of participants. Consider having a preliminary round to narrow down the field before the final competition. 6. Prepare the venue: Ensure that the venue is suitable for the contest. Make sure that there is adequate seating, sound equipment, and lighting for the speakers. 7. Hold the contest: Set a date and time for the contest, and make sure that all participants and judges are aware of the schedule. Encourage audience participation and provide refreshments. 8. Award ceremony: After the contest, hold an award ceremony to recognize the winners and participants. Provide certificates or other prizes to the top performers. I hope these ideas help you in organizing a successful speech contest!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值