[考试总结]noip模拟12

今天总体来说 菜爆了,打了 \(3\) 个暴力,没有一个是正解,并且每一个分数都低得要命。。。

主要还是太菜了。。。

第一题开题发现和昨天 \(T3\) 一样,然而因为还没学可持久化数据结构就咕掉了。。。

昨天要是学一学就好了

然而彭师傅还想出了 \(STL\) 大法。

非常好用。

但是好多人用的还是主席树来维护。

似乎码量也不长。。。

但是我只能弱弱地说一声不会。。。。

菜就是了。。。

所以我今天要去学一学这玩意,以防明天再考

T1:

\(T1\) 又是一个一眼只能 \(\mathcal O(n^3)\) 暴力的玩意。。。

\(\color{red} {\huge{\text{非常不友好}}}\)

但是明显地可以用 单调栈 将其优化为 \(\mathcal O(n^2)\) 的。。。。。。。。。

然而。。。。。。

这个只是最最低分的暴力。。。。

垃圾爆了。。。。

并且出题人很友好毒瘤

暴力给了 \(30\%\)\(\color{red}{\huge{\text{高}}}\) 分。

\(\color{red} {\huge{\text{非常不友好}}}\)

对于 \(Ans\) 我们要求的就是:

\[he_j-he_{j-1}-a_x =0 \]

满足这个式子的 \(i,j\) 位置。

(其中省略了取模)

所以我们只有 \(1e6\) 个取值。

然后在处理前缀和的时候开 \(1e6\)\(vector\) 动态数组。

然后第一个下标是余数,然后第二个动态的是余数为第一个下标的位置

就是:

for(register int i=1;i<=n;++i)
	vec[he[i] % k].push_back(i);

就是这样。

因为我们是按照顺序进行插入下标的,所以我们可以使用 \(lower_bound\) 和 $upper_bound¥ 函数进行二分查找

这就是 \(\mathcal O(log_2^n)\) 的复杂度。

因为我们要先枚举左边或者是右边的区间。

每次选择较小的那个,这样综合起来就是 \(\mathcal O(nlog_2^n)\) 的复杂度。

然后加上二分查找就是 \(O((log_2^n )^2)\)

显然可以过。。。

#include<bits/stdc++.h>
using std::cout; using std::endl;
#define debug cout<<"debug"<<endl;
namespace xin_io
{
	#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1++
	#define scanf eat1 = scanf
	#define freopen eat2 = freopen
	int eat1; FILE *eat2; char buf[1<<20],*p1 = buf,*p2 = buf;
	inline void openfile() {freopen("t.txt","r",stdin);} inline void outfile() {freopen("o.txt","w",stdout);}
	template<class type>inline type get()
	{
		type s = 0,f = 1; register char ch = gc();
		while(!isdigit(ch)) {if(ch == '-') f = -1; ch = gc();}
		while(isdigit(ch))  {s = s * 10 + ch - '0'; ch = gc();}
		return s * f;
	}
}
using namespace xin_io; static const int maxn = 1e6+10,maxb = 110,inf = 0x7f7f7f7f;
#define try(i,a,b) for(register signed i=a;i<=b;++i)
#define throw(i,a,b) for(register signed i=a;i>=b;--i)
typedef long long ll;
namespace xin
{
	int st[maxn],tot = 0,n,k,a[maxn];
	ll ans = 0;
	ll he[maxn];
	std::vector<int>vec[maxn];
	inline void gan(int x,int l,int r)
	{
		if(r - x > x - l)
		{	
			try(i,l,x)
			{
				register int j = (a[x] + he[i-1]) % k;
				int left = std::lower_bound(vec[j].begin(),vec[j].end(),x) - vec[j].begin();
				int right= std::upper_bound(vec[j].begin(),vec[j].end(),r) - vec[j].begin();
				ans += right - left;
//				cout<<"ans = "<<ans<<endl;
			}
		}
		else
		{
			try(i,x,r)
			{
				register int j = (he[i] - a[x] % k + k) % k;
				int right = std::upper_bound(vec[j].begin(),vec[j].end(),x-1) - vec[j].begin();
				int left  = std::lower_bound(vec[j].begin(),vec[j].end(),l-1) - vec[j].begin();
				ans += right - left;
//				cout<<"ans = "<<ans<<endl;
			}
		}
	}
	int l[maxn],r[maxn];
	inline short main()
	{
	#ifndef ONLINE_JUDGE
		openfile();
	#endif
		n = get<signed>(); k = get<signed>();
		try(i,1,n) a[i] = get<signed>(),he[i] = (he[i-1] + a[i]) % k;
		try(i,1,n)
		{
			while(tot and a[i] >= a[st[tot]]) r[st[tot]] = i - 1,tot--;
			l[i] = st[tot] + 1;
			st[++tot] = i;
		}
		while(tot) r[st[tot--]] = n;
//		try(i,1,n) cout<<"l[i] = "<<l[i]<<" r[i] = "<<r[i]<<endl;
		vec[0].push_back(0);
		try(i,1,n) vec[he[i]%k].push_back(i);
		try(i,1,n) gan(i,l[i],r[i]);
		cout<<ans - n<<endl;
		return 0;
	}
}
signed main() {return xin::main();}

T2:

这个题其实式子一眼看出。

然而就是打不对。。。

因为我们还有一个操作: 就是约分。

这个才是最毒瘤的地方。。。

本来我们计算出来值之后乘上一个 \(inv\) 就行了。

但是我们要约分。。。。

不能直接取模,因为是分数。。。。

因为答案的式子是:

\[\frac {A_{2^n}^{m}} {2^{nm}} \]

然后可以发现下面的式子当中约数只有 \(2\)

所以直接搞 \(2\) 就行了。

然后对于 \(2^n\leqm\) 的情况直接计算并输出两个分母就行了。

#include<bits/stdc++.h>
using std::cout; using std::endl;
#define debug cout<<"debug"<<endl;
#define int long long
namespace xin_io
{
	#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1++
	#define scanf eat1 = scanf
	#define freopen eat2 = freopen
	int eat1; FILE *eat2; char buf[1<<20],*p1 = buf,*p2 = buf;
	inline void openfile() {freopen("t.txt","r",stdin);} inline void outfile() {freopen("o.txt","w",stdout);}
	template<class type>inline type get()
	{
		type s = 0,f = 1; register char ch = gc();
		while(!isdigit(ch)) {if(ch == '-') f = -1; ch = gc();}
		while(isdigit(ch))  {s = s * 10 + ch - '0'; ch = gc();}
		return s * f;
	}
}
using namespace xin_io; static const int maxn = 2e6+10,maxb = 110,inf = 0x7f7f7f7f,mod = 1e6+3;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
typedef long long ll;
namespace xin
{
	inline int ksm(int x,int y)
	{
		register int ret = 1;
		while(y)
		{
			if(y & 1) ret = ret * x % mod;
			x = x * x % mod;y >>= 1;
		}
		return ret % mod;
	}
	int n,m;
	inline short main()
	{
	#ifndef ONLINE_JUDGE
		openfile();
	#endif
		std::cin>>n>>m;
		n = n % (mod - 1);
		int ci = 65,fj = 0,pos = 1;
		while(ci--)
		{
			pos <<= 1;
			if(pos >= m) break;
			fj = (fj + (m - 1) / pos) % (mod - 1);
		}
		int inv = ksm(ksm(2,fj),mod-2);
		int ms = ksm(2,n);
		int fm = ksm(ms,(m-1) % (mod - 1)) * inv % mod;
	   	if(m <= mod)
	   	{
	   	    int fz = inv;
	   	    try(i,1,m-1)
	   	        fz = fz*(ms-i+mod)%mod;
	   	    fz = (fm - fz + mod) % mod;
			cout<<fz<<' '<<fm<<endl;
	    }
		else cout<<fm<<' '<<fm<<endl;
		return 0;
	}
}
signed main() {return xin::main();}

T3:

大贪心

然而并不好想出。

我猜你们在考场上都是写了 \(1000\) 多个 \(if\)

然后一个一个手造样例。。。

然而只能拿到 \(10pts\)

一看全都判成 \(-1\) 了。

正解其实是用两个 \(class\)

一个里面是 \(up\) 表示最大的。

然后一个里面是 \(down\) 装上最小的。

这样就行了。

之后算出来的 \(up\)\(down\) 再去反向模拟算答案。

然后愉快骗过\(special\;judge\)

愉快 \(AC\)

细节见代码:

#include<bits/stdc++.h>
using std::cout; using std::endl;
#define debug cout<<"debug"<<endl;
namespace xin_io
{
	#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1++
	#define scanf eat1 = scanf
	#define freopen eat2 = freopen
	int eat1; FILE *eat2; char buf[1<<20],*p1 = buf,*p2 = buf;
	inline void openfile() {freopen("t.txt","r",stdin);} inline void outfile() {freopen("o.txt","w",stdout);}
	template<class type>inline type get()
	{
		type s = 0,f = 1; register char ch = gc();
		while(!isdigit(ch)) {if(ch == '-') f = -1; ch = gc();}
		while(isdigit(ch))  {s = s * 10 + ch - '0'; ch = gc();}
		return s * f;
	}
}
using namespace xin_io; static const int maxn = 2e6+10,maxb = 110,inf = 0x7f7f7f7f;
#define try(i,a,b) for(register signed i=a;i<=b;++i)
#define throw(i,a,b) for(register signed i=a;i>=b;--i)
typedef long long ll;
namespace xin
{
	class xin_data
	{
		public:
			int val,len;
			xin_data(){}
			xin_data(int val,int len):val(val),len(len){}
	}up[maxn],down[maxn];
	int a[maxn],ans[maxn],n,he[maxn];
	inline short main()
	{
	#ifndef ONLINE_JUDGE
		openfile();
	#endif
		n = get<signed>();
		try(i,1,n) a[i] = get<signed>();
		a[1] = 1; up[1] = down[1] = xin_data(1,1);
		try(i,2,n)
		{
			up[i] = xin_data(up[i-1].val,up[i-1].len+1);
			down[i] = xin_data(down[i-1].val,down[i-1].len+1);
			if(up[i].len > 2)
			{
				up[i].val ++;
				up[i].len = 1;
			}
			if(down[i].len > 5)
			{
				down[i].val ++;
				down[i].len = 1;
			}
			if(a[i])
			{
				if(up[i].val == a[i]) up[i].len = std::min(up[i].len,2);
				if(up[i].val > a[i])  up[i] = xin_data(a[i],2);
				if(down[i].val < a[i]) down[i] = xin_data(a[i],1);
				if(up[i].val < a[i] or down[i].val > a[i]) {cout<<-1<<endl; return 0;}
			}
		}
		if(up[n].len == 1) up[n] = xin_data(up[n-1].val,up[n-1].len+1); ans[n] = up[n].val;
		cout<<up[n].val<<endl;
		he[a[n]] = 1;
		throw(i,n-1,0)
		{
			if(a[i]) ans[i] = a[i];
			else
			{
				register int zhuan = std::min(ans[i+1],up[i].val);
				if(he[zhuan] == 5) zhuan --;
				ans[i] = zhuan;
			}
			he[ans[i]] ++;
		}
		try(i,1,n) printf("%d ",ans[i]);
		return 0;
	}
}
signed main() {return xin::main();}

总之,尽力想出能想出的所有。

posted @ 2021-07-12 19:17  NP2Z  阅读(33)  评论(0编辑  收藏  举报