NOI 2023 春季测试

前言

小弱鸡在暑假时候闲的没事尝试打打NOI春季,总分是255分……(有点特殊的含义)

正文

T1:[春季测试 2023] 涂色游戏

非常简单的一道普及题,针对每个操作记录行和列上最近的更新。

在输出的时候查询一下即可。

#include<bits/stdc++.h>
using namespace std;

int T;
int n,m,q;
struct opt{
	int loc, tim;
}qur_1[100005], qur_2[100005];
int main()
{
//	freopen("paint2.in","r",stdin);
//	freopen("paint.out","w",stdout);
	cin>>T;
	while(T){
		T--;
		memset(qur_1,0,sizeof qur_1);
		memset(qur_2,0,sizeof qur_2);
		cin>>n>>m>>q;
		for(int i=1;i<=q;i++){
			int op, lo, col;
			cin>>op>>lo>>col;
			if(op == 0){
				qur_1[lo].loc=col;
				qur_1[lo].tim=i;
			}else{
				qur_2[lo].loc=col;
				qur_2[lo].tim=i;
			}
		}
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				int color;
				if(qur_1[i].tim > qur_2[j].tim){
					color=qur_1[i].loc;
				}else{
					color=qur_2[j].loc;
				}
				if(j!=m) cout<<color<<' ';
				else cout<<color;
			}
			cout<<endl;
		}
	}



	return 0;
}

T2: [春季测试 2023] 幂次

这道题有一点考数论了。

针对1e12以下的数据,我们还可以以接近\(O(\sqrt n)\)的复杂度进行枚举。

但是对于1e18的数据规模,在\(k = 3\)时还可以勉强过关,但\(k = 2\)时就会GG。

所以要先计算\(k = 2\)时的情况为至少\(\sqrt n\),然后再特判\(k = 3\)的情况会不会增加新数。

对于新数的条件,是底数不为完全平方数,且指数为奇数,然后这个数还没有出现过,可以用set来去重。

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
using namespace std;
ll n;
int k;
ll ans;
ll f[100000005];
set<ll> tmp;
map<ll,ll> atp;
ll pre[10000005];
int main()
{
//	freopen("power4.in","r",stdin);
//cout<<pow(99, (double)1.0/6.0);
	cin>>n>>k;
	if(k==1){
		cout<<n<<endl;
		return 0;
	}else if(n<=1e6){

		for(int i=1;pow(i,k)<=n;i++){
			if(i==1) f[1]=1;
			else{
				int cnt=k;
				while(1){
					int hk=pow(i,cnt);
					if(hk>n) break;
					if(hk<=n){
						f[hk]=1;
					}
					cnt++;
				}
			}
		}
		for(int i=1;i<=n;i++){
			if(f[i]){
				ans++;
			}
		}
		cout<<ans;
	}else if(k >= 3){
		for(ll i=1;pow(i,k)<=n;i++){
			if(i==1){
				tmp.insert(1);
			}else{
				for(int j=k;pow(i,j)<=n;j++){
					tmp.insert(pow(i,j));
				}
			}
		}
		cout<<tmp.size()<<endl;
	}else if(k == 2){
		ll ans = sqrtl(n);
		k=3;
		for(int i=1;i<=1000;i++){
			pre[i*i]=1;
		}
		for(ll i=2;pow(i,k)<=n;i++){
			if(tmp.find(i) != tmp.end() || pre[i]) continue;
			for(ll j=k;pow(i,j)<=n;j++){
				if(tmp.find(pow(i,j)) == tmp.end() && j%2 == 1) ans++;
				tmp.insert(pow(i,j));
			}
		}
		cout<<ans<<endl;
	}
	



	return 0;
}

T3: [春季测试 2023] 圣诞树

区间DP,判断从序列的左侧还是右侧添加线段。

注意输入数据保证凸多边形,但是要求是从最高点开始输出,所以开始时要旋转一下,确定最后一个点为起始点。

最后还要判断一下,起始点的位置。

\[f[l][r][0] = \min(f[l+1][r][0] + dis(l,l+1), f[l+1][r][1] + dis(l,r)) \]

\[f[l][r][1] = \min(f[l][r-1][0] + dis(l,r), f[l+1][r][1] + dis(r-1,r)) \]

#include <bits/stdc++.h>
using namespace std;

const int maxn=1005;
struct node{double x,y;int id;}a[maxn],tmp[maxn];
double f[maxn][maxn][2];
int pre[maxn][maxn][2];

double dis(int i,int j){return sqrt((a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y));}

void print(int l,int r,int op)//二分输出
{
    if(l==r) return cout<<a[l].id<<' ',void();
    if(op) cout<<a[r].id<<' ',print(l,r-1,pre[l][r][op]);
    else cout<<a[l].id<<' ',print(l+1,r,pre[l][r][op]);
}

int main()
{
    int n;cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i].x>>a[i].y,a[i].id=i,tmp[i]=a[i];
    int k=1;
    for(int i=2;i<=n;i++) if(a[i].y>a[k].y) k=i;
    for(int i=1;i<=k;i++) a[i+n-k]=tmp[i];
    for(int i=k+1;i<=n;i++) a[i-k]=tmp[i];//题目保证形成凸多边形,所以要旋转
//	swap(a[n],a[k]);
    for(int len=2;len<n;len++)//区间DP,从段长开始
        for(int i=1,j=len;j<n;i++,j++)//左右端点
        {
            f[i][j][0]=f[i][j][1]=1e18;//初始化
            if(f[i][j][0]>f[i+1][j][0]+dis(i,i+1)) f[i][j][0]=f[i+1][j][0]+dis(i,i+1),pre[i][j][0]=0;//四种情况
            if(f[i][j][0]>f[i+1][j][1]+dis(i,j)) f[i][j][0]=f[i+1][j][1]+dis(i,j),pre[i][j][0]=1;
            if(f[i][j][1]>f[i][j-1][0]+dis(j,i)) f[i][j][1]=f[i][j-1][0]+dis(i,j),pre[i][j][1]=0;
            if(f[i][j][1]>f[i][j-1][1]+dis(j,j-1)) f[i][j][1]=f[i][j-1][1]+dis(j,j-1),pre[i][j][1]=1;
        }
    cout<<a[n].id<<' ';//最高点
    if(f[1][n-1][0]+dis(1,n)>f[1][n-1][1]+dis(n-1,n)) print(1,n-1,1);//最后是右还是左,经过所有顶点恰好一次
    else print(1,n-1,0);
    return 0;
}
posted @ 2024-08-23 16:13  SSZX_loser_lcy  阅读(18)  评论(0编辑  收藏  举报