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

noip模拟4

时间:2024-11-03 14:45:38浏览次数:2  
标签:cnt noip int -- while tp1 ans 模拟

A Median

打了 \(70\) 分,但是因为 printf("%.1lf") 惨遭爆零。

原因详见我写的讨论。

首先,你需要把 \([1,10^7]\) 范围是质数全部筛出来,大概耗时半秒。

然后,考虑数据是根据质数构造的,所以近似为随机。

那么既然随机,那咱们直接对于每次移动去维护中位数的位置就好了。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1.1e7+7,M=5e5+5,K=180000000;
//180000000
bitset<K>vis;
bitset<K>isp,p1;
int p[N];
int ccnt;
int ans;
inline void init(int n)
{
	for(int i=2;i<=n;i++)
	{
		if(!vis[i]) p[++ccnt]=i;
		for(int j=1;1ll*i*p[j]<=n;j++)
		{
			vis[i*p[j]]=1;
			if(i%p[j]==0) break;
		}
	}
}
int n,k,w;
int s[N],s2[N];
int sub[N];
const int mx=1e7;
int cnt[N];
namespace sub1{
	inline void init2(int n)
	{
		for(int i=2;i<=n;i++)
		{
			if(!isp[i])
			{
				p1[++ccnt]=(i%3==2?1:0);
				for(int j=2;j*i<=n;j++) isp[j*i]=1;
			}
		}
	}
	int c[6];
	void Q()
	{
		init2(180000000);
		p1[2]=0,p1[1]=2,s2[0]=5;
		for(int i=1;i<=n;i++)
		{
			if(i==2)
			{
				s[i]=0,s2[i]=s[i/10+1];
				continue;
			}
			s[i]=((p1[i]==1?2:1)*i)%w;
			s2[i]=s[i]+s[i/10+1];
		}
		for(int i=0;i<k;i++)c[s2[i]]++;
		double ans=0;
		for(int i=1;i<=n-k+1;i++)
		{
			c[s2[i-1]]--,c[s2[i+k-1]]++;
			if(k%2==1)
			{
				int mid=(k+1)/2,lcnt=0,j=0;
				for(;j<=4;j++)
				{
					lcnt+=c[j];
					if(lcnt>=mid) break;
				}
				ans+=j;
			}
			else
			{
				int mid=k>>1,lcnt=0,j=0;
				double res=0;
				for(;j<=4;j++)
				{
					lcnt+=c[j];
					if(lcnt>mid) 
					{
						res=j;break;
					}
					else if(lcnt==mid)
					{
						int k=j+1;
						while(!c[k])k++;
						res+=(double)(j+k)/2.0;
						break;
					}
				}
				ans+=res;
			}
		}
		printf("%.1f",ans);
		exit(0);
	}
}
signed main()
{
	freopen("median.in","r",stdin);
	freopen("median.out","w",stdout);
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	cin>>n>>k>>w;
	if(w==3)sub1::Q();
	init(180000000);
	for(int i=1;i<=n;i++) 
	s[i]=(p[i]*i%w),s2[i]=s[i]+s[i/10+1];
	for(int i=1;i<=k;i++) cnt[s2[i]]++;
	if(k&1)
	{
		int sum=0,tp1=0,tp2=0,cnt1=0,cnt2=0;
		for(int i=1;i<=mx;i++)
		{
			sum+=cnt[i];
			if(sum>=k/2+1)
			{
				cnt1=sum-cnt[i],cnt2=k-sum;
				tp1=tp2=i;
				break;
			}
			if(cnt[i]) tp1=i;
		}
		ans+=tp1+tp2;
		int num=k/2;
		for(int i=1;i<=n-k;i++)
		{
			int lst=s2[i],now=s2[i+k];
			cnt[lst]--,cnt[now]++;
			cnt1+=-(lst<tp1)+(now<tp1);
			cnt2+=-(lst>tp1)+(now>tp1);
			while(cnt1>num)
				cnt2+=cnt[tp1],tp1--,cnt1-=cnt[tp1];
			while(cnt2>num)
				cnt1+=cnt[tp1],tp1++,cnt2-=cnt[tp1];
			ans+=tp1*2;
		}
	}
	else
	{
		int num=k/2,cnt1=0,cnt2=0;
		int tp1=-1,tp2=-1;
		for(int i=k;i<=n;i++)
		{
			if(i!=k) cnt[s2[i]]++;
			if(s2[i]<=tp1) cnt1++;
			if(s2[i]<=tp2) cnt2++;
			if(i>k)
			{
				cnt[s2[i-k]]--;
				if(s2[i-k]<=tp1) cnt1--;
				if(s2[i-k]<=tp2) cnt2--;
			}
			while(cnt1<num) cnt1+=cnt[++tp1];
			while(cnt2<=num) cnt2+=cnt[++tp2];
			while(cnt1>=num+cnt[tp1]) cnt1-=cnt[tp1--];
			while(cnt2>=num+1+cnt[tp2]) cnt2-=cnt[tp2--];
			ans+=tp1+tp2;
		}
	}
	if(ans&1) cout<<ans/2<<".5";
	else cout<<ans/2<<".0";
}

B Game

太可恶了。考场上差点打出来,结果忽然不想打了,痛失 50。

\(\log\) 做法是显然的。拿优先队列每次取出队头久好了。

但是 \(O(nk\log n)\) 不能接受啊。

那其实我们可以从值域下手。

维护最大值,每次暴力地看最大值是否被修改,如果修改,则更新最大值。

这时候最大值只可能是被取走,因为如果当前值比最大值还要大,那么你会优先取走这个。

因此,序列中维护的最大值是单调不增的。

那我们维护一次就是 \(O(n)\),总复杂度 \(O(nk)\)。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,k;
const int N=1e6+6;
int a[N], t[N];
signed main()
{
	freopen("game.in","r",stdin);
	freopen("game.out","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	cin>>n>>k;
	for(int i=1;i<=n;i++) cin>>a[i];
	while(k--)
	{
		int cnta=0,cntb=0;
		int p;cin>>p;
		int mx=0;
		for(int i=1;i<p;i++) t[a[i]]++,mx=max(mx,a[i]);
		int stp=0;
		for(int i=p;i<=n;i++)
		{
			stp++;
			if(a[i]>=mx) stp%2==1?cnta+=a[i]:cntb+=a[i];
			else
			{
				t[a[i]]++,t[mx]--;
				(stp)%2==1?cnta+=mx:cntb+=mx;
				while(!t[mx])--mx;
			}
		}
		for(int i=mx;i>=1;i--)
		{
			while(t[i])
			{
				(++stp)%2==1?cnta+=i:cntb+=i;
				t[i]--;
			}    
		}
		cout<<cnta-cntb<<"\n";
	}
	return 0;
}

C Park

树形 dp,我不会。

点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
	register char ch=getchar();register int x=0;
	while(ch<'0'||ch>'9')ch=getchar();
	while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return x;
}
const int N=1e5+5,V=105;
int n,v,ans,a[N],f[N][V][2],g[N][V][2];
vector<int>G[N];
void dfs(int x,int p){
	f[x][0][1]=g[x][0][1]=-1e16;
	int sum=0;
	for(int i=0;i<G[x].size();i++){
		int y=G[x][i];
		if(y==p)continue;
		dfs(y,x);
		sum+=a[y];
	}
	g[x][1][1]=sum+a[p];
	for(int i=0;i<G[x].size();i++){
		int y=G[x][i];
		if(y==p)continue;
		int mxf=-1e16,mxg=-1e16;
		for(int j=v;j>=0;j--){
			mxf=max(mxf,max(f[x][v-j][0],f[x][v-j][1]+a[p]-a[y])),
			mxg=max(mxg,max(g[x][v-j][0],g[x][v-j][1]));
			ans=max(ans,mxg+max(f[y][j][0],f[y][j][1]));
			ans=max(ans,mxf+max(g[y][j][0],g[y][j][1]));
		}
		for(int j=1;j<=v;j++){
			f[x][j][0]=max(f[x][j][0],max(f[y][j][0],f[y][j][1])),
			g[x][j][0]=max(g[x][j][0],max(g[y][j][0],g[y][j][1]));
			f[x][j][1]=max(f[x][j][1],max(f[y][j-1][0],f[y][j-1][1])+sum),
			g[x][j][1]=max(g[x][j][1],max(g[y][j-1][0],g[y][j-1][1])+sum-a[y]+a[p]);
		}
	}
}
signed main(){
	freopen("park.in","r",stdin);
	freopen("park.out","w",stdout);
	n=read(),v=read();
	for(int i=1;i<=n;i++)a[i]=read();
	for(int i=1,u,v;i<n;i++){
		u=read(),v=read();
		G[u].push_back(v);
		G[v].push_back(u);
	}
	dfs(1,0);
	cout<<ans;
}

D 路径

变形金刚。

image

我只会 \(35\),\(O(n^2 \log n)\) 暴力和 \(k=1\) 的 dp。。。

标签:cnt,noip,int,--,while,tp1,ans,模拟
From: https://www.cnblogs.com/ccjjxx/p/18523397

相关文章

  • noip模拟3
    这场好难。A网格队列里的结构体数组开大了导致RE。。。正解很简洁,对于现在有的字符串,添加一个数字或符号的转移是相对固定的:添加一个数字,如果前一位是运算符,那么久新加一个数字,否则,让现在的数字乘以10加上它;添加运算符同理。点击查看代码#include<bits/stdc++.h>us......
  • 【STL_list 模拟】——打造属于自己的高效链表容器
    一、list节点​list是一个双向循环带头的链表,所以链表节点结构如下: template<classT> structListNode { Tval; ListNode*next; ListNode*prve; ListNode(intx) { val=x; next=prve=this; } };二、list迭代器2.1、list迭代器与vector......
  • 2024.11.2 模拟赛
    2024.11.2模拟赛T1P11242碧树把\(n\)个点往外连即可。最终答案为\(n-\max_{i=1}^na_i+1\)T2P11243繁花感觉我的做法麻烦了,而且随机复杂度()显然的,从左往右看可以分层,遇到一次大于号分一次。对于每段,遍历一遍,每遇到一次小于号计算一次答案。如果不考虑等于号,这段的......
  • strlen函数的模拟实现
    首先我们先新建项目,并新建源文件然后先调用sring.h里的strlen函数看看该函数的效果可以看到strlen的结果为字符串"abc"的长度我们又知道对于字符串"abc"实际上在字符串尾部会存在\0,即字符串arr实际上是"abc\0"那么先定义自定义函数my_strlen使它的返回类型为int,接受的数组......
  • 易语言模拟真人动态生成鼠标滑动路径
    一.简介鼠标轨迹算法是一种模拟人类鼠标操作的程序,它能够模拟出自然而真实的鼠标移动路径。鼠标轨迹算法的底层实现采用C/C++语言,原因在于C/C++提供了高性能的执行能力和直接访问操作系统底层资源的能力。鼠标轨迹算法具有以下优势:模拟人工轨迹:算法能够模拟出非贝塞尔曲线的......
  • Python模拟真人动态生成鼠标滑动路径
    一.简介鼠标轨迹算法是一种模拟人类鼠标操作的程序,它能够模拟出自然而真实的鼠标移动路径。鼠标轨迹算法的底层实现采用C/C++语言,原因在于C/C++提供了高性能的执行能力和直接访问操作系统底层资源的能力。鼠标轨迹算法具有以下优势:模拟人工轨迹:算法能够模拟出非贝塞尔曲线的......
  • C++模拟真人动态生成鼠标滑动路径
    一.简介鼠标轨迹算法是一种模拟人类鼠标操作的程序,它能够模拟出自然而真实的鼠标移动路径。鼠标轨迹算法的底层实现采用C/C++语言,原因在于C/C++提供了高性能的执行能力和直接访问操作系统底层资源的能力。鼠标轨迹算法具有以下优势:模拟人工轨迹:算法能够模拟出非贝塞尔曲线的......
  • 《冰汽时代2》为何叫刁民模拟器?《冰汽时代2》详细玩法介绍
    《冰汽时代2》(Frostpunk2)是11bitstudios开发的一款城市建造和生存策略游戏,是2018年大受好评的《冰汽时代》的续作。这款游戏在发布前就受到了广泛关注,部分玩家戏称其为“刁民模拟器”,这主要是因为原作中的一些特点:为什么叫“刁民模拟器”?1.道德抉择:在《冰汽时代》中,玩家......
  • json-server详细模拟GET、POST、DELETE等接口数据教程
    引言在前端开发过程中,我们经常需要在后端API尚未就绪的情况下模拟接口数据。json-server是一个强大而灵活的工具,可以帮助我们快速创建一个模拟的RESTfulAPI。本文将详细介绍如何使用json-server来模拟GET、POST、PUT、PATCH、DELETE等常用的HTTP方法,以及如何处理复杂的数......
  • 单双链表(数组模拟)笔记
    单双链表(数组模拟)笔记如题,我们要使用数组来模拟链表这个数据结构区别于传统的结构体链表(动态链表):structnode{ intvalue; structnode*next;//指向下一个节点的指针}user_define_name;//调用链表的别称数组模拟链表(静态链表)的速度更快,但是对于空间的优化不如动态链表......