首页 > 其他分享 >noip模拟22

noip模拟22

时间:2024-11-27 20:45:38浏览次数:8  
标签:柱子 22 noip int long ansa ansb now 模拟

今天是用 2020 年的 NOIP 模拟的。T2 被换掉了,因为之前专题做过,然后换了个更好做的?

也是有了自己的 200+。

ps:没有按难度排序。

A [NOIP2020] 微信步数

B [NOIP2020] 移球游戏

神秘构造题,但其实思路很简单。

考虑一种接口化,或者说模块化的解法,使得我能利用一些柱子实现某一个数只出现在某一个柱子上。

打个比方,这就像魔方一样,可以构造一个特定的公式,使得一些数交换位置而其他数不受影响。

Step 1 制造全 \(0\) 列

首先,假设当前要处理的元素是 now,那我们就把所有 now 标记成 \(1\),其他标记成 \(0\)。

然后考虑一个事情,如何把一个序列的 \(0\) 和 \(1\) 分开?

记第 \(i\) 根柱子上的 \(i\) 的个数为 \(tot_i\),我们可以先把第 \(n\) 个柱子上的前 \(tot_i\) 个移动到 \(n+1\)(空柱子)上

image

然后将第一列的 \(1\) 挪到第 \(n\) 列,其他 \(0\) 挪到第 \(n+1\) 列。

image

将第 \(n+1\) 列的前 \(m-tot_i\) 个 \(0\) 挪回第 \(1 列\)

image

然后,将第 \(2\) 列的 \(0\) 分裂到第 \(1\) 列和第 \(n+1\) 列。

image

然后就会发现第 \(2\) 列没有数了,第 \(1\) 列成了全 \(0\) 列。

注意到原本定义的列数发生错位了,我们可以用 \(p_i\) 标记 \(i\) 列的原始编号。这样在进行完上述操作之后就需要交换 \(1\) 和 \(n\) 的编号和 \(2\) 和 \(n+1\) 的编号。

Step 2 构造全 \(1\) 列

我们在上述操作中已经构造出来一个全 \(0\) 的序列,并已经使得 \(1\) 号柱子上的全部 \(1\) 都到了 \(n\) 号柱子的最上方。重复以上过程就会使全部的 \(1\) 出现在所有序列上方,把它放到那个空序列就行。

处理 \(n=2\) 的情况

其实很简单,和上述思路类似,把前 \(tot\) 的放在 \(3\) 号,把 \(1\) 号柱子分裂在 \(2\) 号和 \(3\) 号上,再把分裂后的回填回 \(1\),这样 \(1\) 柱子就上下分层了,把 \(3\) 填到 \(2\) 上,就好了。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n;
const int N=401;
int stk[51][N],top[51];
int tot[51];
vector<pair<int,int> >ans;
int p[51];
//
//void calc(int col,int a,int b,int c,int d)
//{
//	for(int i=1;i<=tot[p[a]];i++)
//	{
//		
//	}
//}
inline void move(int a,int b)
{
	ans.push_back({a,b});
	stk[b][++top[b]]=stk[a][top[a]--];
}
int m;
inline int tp(int a)
{
	return stk[a][top[a]];
}
signed main()
{
	freopen("ball.in","r",stdin);
	freopen("ball.out","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		p[i]=i;
		for(int j=1;j<=m;j++) cin>>stk[i][j];
		top[i]=m;
	}
	p[n+1]=n+1;
	top[n+1]=0;
	for(int now=n;now>=3;now--)
	{
		int tmp=0;
		for(int k=1;k<=m;k++)tmp+=(stk[p[1]][k]==now);
		for(int i=1;i<=tmp;i++)move(p[now],p[now+1]);
		for(int i=1;i<=m;i++)
		{
			if(tp(p[1])==now) move(p[1],p[now]);
			else move(p[1],p[now+1]);
		}
		for(int i=1;i<=m-tmp;i++) move(p[now+1],p[1]);
		for(int i=1;i<=m;i++)
		{
			if(tp(p[2])==now||top[p[1]]==m) move(p[2],p[now+1]);
			else move(p[2],p[1]);
		}
		swap(p[1],p[now]),swap(p[2],p[now+1]);
		for(int k=1;k<now;k++)
		{
			tmp=0;
			for(int j=1;j<=m;j++)tmp+=(stk[p[k]][j]==now);
			for(int i=1;i<=tmp;i++)move(p[now],p[now+1]);
			for(int i=1;i<=m;i++)
			{
				if(tp(p[k])==now) move(p[k],p[now]);
				else move(p[k],p[now+1]);
			}
			swap(p[k],p[now+1]);
			swap(p[k],p[now]);
		}
		for(int i=1;i<now;i++) while(tp(p[i])==now) move(p[i],p[now+1]);
		for(int i=1;i<now;i++) while(top[p[i]]<m) move(p[now],p[i]);
	}
//	cerr<<ans.size()<<"\n";
	int tmp=0;
	for(int k=1;k<=m;k++)tmp+=(stk[p[1]][k]==1);
	for(int i=1;i<=tmp;i++)move(p[2],p[3]);
	for(int i=1;i<=m;i++)
	{
		if(tp(p[1])==1) move(p[1],p[2]);
		else move(p[1],p[3]);
	}
	for(int i=1;i<=tmp;i++) move(p[2],p[1]);
	for(int i=1;i<=m-tmp;i++) move(p[3],p[1]);
	while(top[p[3]]) move(p[3],p[2]);
	while(tp(p[1])==2) move(p[1],p[3]);
	for(int i=1;i<=m;i++)
	{
		if(tp(p[2])==1) move(p[2],p[1]);
		else move(p[2],p[3]);
	}
	cout<<ans.size()<<"\n";
	for(auto i:ans) cout<<i.first<<" "<<i.second<<"\n";
}

C [NOIP2020] 排水系统

这才是真正的 T1。开考半个小时切了。

按题意模拟即可。但是会爆 long long,这给我提了个醒,当大样例答案特别大,但是没超 long long 的时候,一定要自己再搓一个更大的样例,看看会不会超范围。如果超了果断换 int128 或者写高精。其实有个更冒险的做法是用 long double,虽然存储范围很大,但是越大精度越低。

所以还是用 int128 比较好。

后记:题目没卡深搜,其实最正确的做法是拓扑排序,遇到入度为 \(0\) 的点就放水,直到最后。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int __int128
int n,m;
const int N=1e5+5;
vector<int>e[N];
int indeg[N],outdeg[N];
int ansa[N],ansb[N];
int lcm(int x,int y)
{
	if(x==0||y==0) return 1;
	return x/__gcd(x,y)*y;
}
inline void add(int u,int a,int b)
{
	int lc=lcm(ansb[u],b);
	ansa[u]=ansa[u]*(lc/ansb[u]);
	ansb[u]=lc;
	a=a*(lc/b);
	ansa[u]+=a;
	int gc=__gcd(ansa[u],ansb[u]);
	ansa[u]/=gc,ansb[u]/=gc;
}
void dfs(int u,int a,int b)
{
	for(int v:e[u])
	{
		if(!outdeg[v])
		add(v,a,b*outdeg[u]);
		dfs(v,a,b*outdeg[u]);
	}
}
inline int read()
{
	register int s=0;
	register char c=getchar();
	while(c<'0'||c>'9') c=getchar();
	while(c>='0'&&c<='9') s=(s<<1)+(s<<3)+(c^48),c=getchar();
	return s;
}
void write(int x)
{
	if(x>9) write(x/10);
	putchar(x%10+'0');
}
signed main()
{
	freopen("water.in","r",stdin);
	freopen("water.out","w",stdout);
	n=read(),m=read();
	for(int i=1;i<=n;i++)
	{
		ansb[i]=1;
		int d=read();
		for(int j=1;j<=d;j++)
		{
			int v=read();
			outdeg[i]++,indeg[v]++;
			e[i].push_back(v);
		}
	}
	for(int i=1;i<=n;i++)
	{
		if(indeg[i]==0) dfs(i,1,1);
	}
	for(int i=1;i<=n;i++)
	{
		if(!outdeg[i]) write(ansa[i]),putchar(' '),write(ansb[i]),putchar(10); 
	}
}

D 三元组

\(O(n^3)\) 的暴力是好想的,\(O(nk)\) 的性质是好做的。

merge 起来就有 \(60\) 分。

设 \(dp[i][j]\) 表示到第 \(i\) 个数时 \(a+b^b\)(其中 \(a\in[1,i]b\in[a,i]\))余数为 \(k\) 的数量。因为每新加入一个 \(i\) 就相当于新加入点对 \((1,i),(2,i)\cdots (i,i)\),也就是所有 \(i^2+1\) 到 \(i^2+i\) 模 \(k\) 余数的个数加一。\(dp[i][j]=dp[i-1][j]+b[j]\),其中 \(b[j]\) 表示新加入点对中余数为 \(j\) 的个数。答案就是 \(\displaystyle \sum_{i=1}^n dp[i][i^3 \text{ mod }k]\)。

可以滚一下,降低空间复杂度。

然后发现可以拿树状数组维护值域区间 \([0,k)\),就是每次在上述区间上区间加 \(1\),并给重复的整块加上 \(\lfloor \frac i k\rfloor\),用区修单查树状数组就实现了。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+5;
int n,k;
int *c;
struct SegTree{
	inline int lowbit(int x)
	{
		return x&-x;
	}
	void update(int x,int K)
	{
		x++;
		for(;x<=k;x+=lowbit(x)) c[x]+=K;
	}
	void Update(int l,int r,int K)
	{
		update(l,K),update(r+1,-K);
	}
	int query(int x)
	{
		x++;int res=0;
		for(;x;x-=lowbit(x)) res+=c[x];
		return res;
	}
}st;
void q()
{
	cin>>n>>k;
	c=new int [k+10];
	for(int i=0;i<=k+9;i++) c[i]=0;
	int ans=0,tmp=0;
	for(int i=1;i<=n;i++)
	{
		int l=(i*i+1),r=i*(i+1);
		l%=k,r%=k;
		tmp+=i/k;
		if(i%k)
		{
			if(l>r) st.Update(0,r,1),st.Update(l,k-1,1);
			else st.Update(l,r,1);
		}
		ans+=st.query((i*i%k*i)%k)+tmp;
	}
	cout<<ans<<"\n";
}
signed main()
{
	freopen("exclaim.in","r",stdin);
	freopen("exclaim.out","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	int T;cin>>T;
	for(int i=1;i<=T;i++) cout<<"Case "<<i<<": ",q();
}

标签:柱子,22,noip,int,long,ansa,ansb,now,模拟
From: https://www.cnblogs.com/ccjjxx/p/18573017

相关文章

  • 代码随想录算法训练营第十四天(统一迭代;LeetCode226.翻转二叉树;LeetCode101.对称二叉树
    统一迭代LeetCode144.二叉树的前序遍历题目链接:二叉树的前序遍历题目链接代码/***Definitionforabinarytreenode.*publicclassTreeNode{*intval;*TreeNodeleft;*TreeNoderight;*TreeNode(){}*TreeNode(intval)......
  • NOIP2024加赛8
    NOIP2024加赛8题目来源:2023NOIPA层联测32\(T1\)HZTG5781.flandre\(100pts\)先将\(\{a\}\)升序排序并去重后,由调整法可知选取的数一定是一段后缀。正数的贡献肯定是无脑全加上,难点在于负数中多次出现的数的选择。不妨钦定答案序列中选择的最小的数,通过需要加......
  • NOIP2024 加赛 8
    骗你的,没写。不过这场分比较高,前三道切的都挺顺,T4也拿了暴力分。T3和题解的处理办法不太一样,具体就是没有统计每条边的贡献,树上DP求的是子树内的答案,处理修改的时候也不一样。就挂个代码吧。#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongusing......
  • [75] (NOIP集训) NOIP2024 加赛 8
    A.flandre我的做法是,所有数离散化之后扔进桶里,去枚举选择\([i,+\infty)\)内的数的贡献,在所有的\(i\)里取一个最大值作为答案lbtl指出可能存在最优答案是选择\([i+1,+\infty)\)内的所有数与值为\(i\)的部分数的数据和lbtl交涉后尝试构造一组相同元素只选后一半的数据......
  • NOIP2024加赛8
    状态很不好,恼了。虚拟机太卡了,根本交不上去。flandre发现选取的肯定是从大到小排序后的一个后缀,然后就做完了,时间复杂度\(O(n\logn)\)。点此查看代码#include<bits/stdc++.h>usingnamespacestd;#definerep(i,s,t,p)for(inti=s;i<=t;i+=p)#definedrep(i,s,t,p......
  • 1127noip模拟赛(命运fate)
    智慧t2,我不智慧,赛时想到了一点点。。题意:给一个单调不降的序列\(a_1,a_2,...,a_n\)。给定一个整数\(x\)。求一个\(b\)序列使得任意\(\foralli(1<i\len)\a_i-b_i<a_{i+1}-b_{i+1}\)且\(\foralli<j<x\\b_i\leb_j.\forallx<j<i\\b_i\leb_j\)。做法:整理一......
  • #20222309 2024-2025-1 《网络与系统攻防技术》实验五实验报告
    1.实验内容(1)从www.besti.edu.cn、baidu.com、sina.com.cn中选择一个DNS域名进行查询,获取如下信息:DNS注册人及联系方式该域名对应IP地址IP地址注册人及联系方式IP地址所在国家、城市和具体地理位置PS:使用whois、dig、nslookup、traceroute、以及各类在线和离线工具进行搜集信......
  • 多校A层冲刺NOIP2024模拟赛26 && G
    多校A层冲刺NOIP2024模拟赛26&&GT1随机游走考虑到达一个点后,我们该往他的那个儿子走,简单膜一下只有两个儿子的样例后发现条件是$\frac{w_i}{v_i}$越小越优先,其中$w_i$表示他到父亲的边权,$v_i$表示他的点权,然后尝试推广,膜个稍微大点的样例发现完全是通用的,此时......
  • Time Stop#NOIP2024/GDUTCPC
    重要声明:本文章从2024.11.2716:12开始落笔,故cnblogs平台显示的上传时间会在NOIP2024比赛之前。本文章作者不存在任何以各类非合法渠道提前获取NOIP2024比赛题目的可能,同时也没有将该想法实现对应的资源或权力。请各位读者作证,并请相关组织明察。Day-3/2024.11.27这......
  • CudaSPONGE高性能GPU分子模拟
    技术背景CudaSPONGE是基于CUDAC开发的一款纯GPU分子动力学模拟软件,具有模块化和高性能的特点。官方基本介绍内容如下:分子动力学(MolecularDynamics,MD)模拟是化学、物理学、生物学、材料科学和许多其他领域的有用工具。在过去40年中,人们开发了各种高效的计算算法和MD程序,用......