noip模拟10

发现是前几天早上那场 MX(美熙) 的模拟赛,但是没做。

A 王国边缘

其实知道是倍增题。但是想不出来怎么个倍增法。

于是用分块打上了部分分 \(70\) 分。

我们用倍增设 \(f_{i,j}\) 表示从 \(i\) 开始移动 \(2^j\) 次之后到达的下标的相对位置,\(g_{i,j}\) 表示从 \(i\) 开始移动 \(2^j\) 次后到达的位置之前的完整周期个数。

\[\begin{cases} f_{i,j}=f_{f_{i,j-1},j-1} \\ g_{i,j}=g_{i,j-1}+g_{f_{i,j-1},j-1} \end{cases} \]

然后对询问二进制拆分即可。

当然也可以把循环周期当作一个个有向边,在基环树上跑倍增。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e5+5;
const int mod=1e9+7;
int n,q,m,s[N],t[60][N],t2[60][N];
signed main()
{
//	ios::sync_with_stdio(false);
//	cin.tie(0),cout.tie(0);
	cin>>n>>m>>q;
	int l=-m;
	for(int i=0;i<n;i++)
	{
		char c;cin>>c;
		if(c=='1') s[i]=i,l=i;
		else s[i]=l;
	}
	if(l!=-m)
	{
		for(int i=0;i<n&&s[i]==-m;i++)s[i]=l-n;
	}
	
	for(int i=0;i<n;i++)
	{
		int k=(i+m)%n;
		t[0][i]=max(i+m-k+s[k],i+1);
		t2[0][i]=t[0][i]%n;
		t[0][i]%=mod;
	}
//	cout<<"sss\n";
	for(int i=1;i<60;i++)
	{
		for(int j=0;j<n;j++)
		{
			int k=t2[i-1][j];
			t2[i][j]=t2[i-1][k];
			t[i][j]=(t[i-1][k]-k+t[i-1][j])%mod;
		}
	}
	while(q--)
	{
		int s,k,s2;
		cin>>s>>k;
		s--;s2=s%n;
		for(int i=0;k;k>>=1,i++)
		{
			if(k&1)
			{
				s=(t[i][s2]+s-s2)%mod;
				s2=t2[i][s2];
			}
		}
		cout<<(s+1)%mod<<"\n";
	}
	
}

B 买东西题

知道是贪心,但是不知道怎么贪。。。

考场上想到了维护每个数的价差 \(c_i=a_i-b_i\),并且知道对于一个所有可用的优惠券集合,匹配最优的一定是价差最大的与优惠券减价最多的。

但是没想到可以看作每个数的价差也应该视作一张优惠券(其实猜到了,没敢想),一起维护在优惠券集合内,当你现在要反悔,第 \(i\) 个点要拿走第 \(j\) 个点的优惠券,那么他应该交换而不是直接拿。就是把 \(i\) 的价差维护进优惠券集合,拿走 \(j\) 的优惠券,就好了。

为了保证优惠券一定可用,就需要把优惠券和商品分别按 \(a\) 升序排列,依次将前缀的优惠券加入优先队列中维护。

和正解就差一行代码!!!

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m;
const int N=1e6+5;
struct node1{
	int a,b;
	inline bool operator<(const node1 &ll) const{
		if(ll.b==b) return ll.a>a;
		return ll.b>b;
	}
}c[N];
struct node{
	int a,b,c;
	inline bool operator<(const node &ll) const{
		if(ll.c==c) return ll.a>a;
		if(ll.a==a) return ll.b>b;
		return ll.c<c;
	}
}e[N];

inline bool cmp(node a,node b)
{
//	if(a.a==b.a) return a.b>b.b;
//	return min(a.a,b.a)>min(a.b,b.b);
	if(a.a==b.a) return a.b>b.b;
	return a.a<b.a;
}
inline bool cmp1(node1 a,node1 b)//实际上这几个是一样的,只是在不同的部分分和结构体内。
{
	if(a.a==b.a) return a.b>b.b;
	return a.a<b.a;
}
inline bool cmp2(node a,node b)
{
//	if(a.a==b.a) return a.b>b.b;
//	return min(a.a,b.a)>min(a.b,b.b);
	if(a.a==b.a) return a.b<b.b;
	return a.a<b.a;
}
inline bool cmp3(node1 a,node1 b)
{
	if(a.a==b.a) return a.b<b.b;
	return a.a<b.a;
}
priority_queue<node1>q;
priority_queue<node>q1;//实际上没有用到它

signed main()
{
//	freopen("buy5.in","r",stdin);
	freopen("buy.in","r",stdin);
	freopen("buy.out","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	cin>>n>>m;
	bool _=1;
	for(int i=1;i<=n;i++) cin>>e[i].a>>e[i].b,e[i].c=(e[i].a-e[i].b),_&=(e[i].a==e[i].b);
	for(int i=1;i<=m;i++) cin>>c[i].a>>c[i].b;
	if(_||n<=10)
	{
		sort(e+1,e+1+n,cmp);
		sort(c+1,c+1+m,cmp1);
		int ans=0,cnt=0;
		for(int i=1,j=1;i<=n;i++)
		{
			while(c[j].a<=e[i].a&&j<=m)q.push(c[j++]);
	//		cout<<j<<" ";
			if(!q.empty()&&e[i].a-q.top().b<e[i].b) ans+=e[i].a-q.top().b,q.pop(),++cnt;
			else ans+=e[i].b;
	//		cout<<"c: "<<c[i].a<<" "<<c[i].b<<"\n";
//			cout<<"e: "<<e[i].a<<" "<<e[i].b<<"\n";
//			cout<<ans<<"\n";
		}
		cout<<ans;return 0;
	}
	sort(e+1,e+1+n,cmp2);
	sort(c+1,c+1+m,cmp3);
	int ans=0,cnt=0,j=1;
	for(int i=1;i<=n;i++)
	{
		while(j<=m&&c[j].a<=e[i].a) q.push(c[j++]);
		if(q.empty()||e[i].c>q.top().b) ans+=e[i].b;
		else ans+=e[i].a-q.top().b,q.pop(),q.push({1,e[i].a-e[i].b});//就是这个 push 没写出来
	}
//	for(int i=1;i<=n;i++) q1.push(e[i]);
//	for(int i=1;i<=m;i++) q.push(c[i]);
//	while(!q1.empty())
//	{
//		if(q.top().b<q1.top().c) ans+=q1.top().b,q1.pop();
//		else ans+=q1.top().a-q.top().b,q.pop(),q1.pop();
//	}
	cout<<ans;//其他的都是奇奇怪怪的假做法和部分分。
//	for(int i=1;i<=n;i++) cout<<"q "<<q1.top().a<<" "<<q1.top().b<<"\n",q1.pop();
//	return 0;
//	for(int i=1;i<=m;i++)
//	{
//		while(c[i].a<=e[j].a&&j<=n)q1.push(e[j++]);
////		cout<<i<<" ";
////		cout<<q1.top().a<<" "<<q1.top().b<<"\n";
////		cout<<"c: "<<c[i].a<<" "<<c[i].b<<"\n";
//		q.push(c[i]);
//		if(!q1.empty()&&q1.top().c<q.top().b)ans+=q1.top().a-q.top().b,q1.pop(),++cnt,q.pop();
//		else if(!q1.empty())ans+=q1.top().b,q1.pop();
////		cout<<"ans: "<<ans<<"\n";
//	}
////	cout<<ans<<"\n";
////	cout<<j<<"\n";
//	for(int i=j;i<=n;i++) q1.push(e[i]);
//	while(!q1.empty()) ans+=q1.top().b,q1.pop();
//	cout<<ans;
}

C IMAWANOKIWA (Construction ver.)

分讨+构造。

首先,对于 ans1,有结论:

  • 当且仅当 \(a\) 全为 \(0\) 时答案为 \(0\)

  • 序列 \(a\) 没有 \(0\) 时答案为 \(2\) 的个数对 \(2\) 取模的余数+1;

  • 否则,当且仅当序列 \(a\)\(1,1,1,1...1,2,0,2,1,...1,1,1\)(其中 \(1\) 可用没有)的形式时,答案为 \(2\),否则为 \(1\)

还有结论,第一个能合并的位置移动不超过 \(3\)

那么就可以每次合并前几个,用上面的三个结论试一下答案是否会被改变,如果没有那么保留。

好像有 \(61\) 分。

tj:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ull unsigned long long
const int N=100007,op[3][3]={{0,1,1},{1,1,2},{1,2,1}};
const ull pp=13331;
int T,n,a[N],k,p,last0;
char s[N];
ull ans;
signed main()
{
	freopen("popc.in","r",stdin);
	freopen("popc.out","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	cin>>T;
	while(T--)
	{
		cin>>(s+1);
		n=strlen(s+1);
		k=a[1]=s[1]-'0',ans=0;
		for(int i=2;i<=n;++i)
			a[i]=s[i]-'0',k=op[k][a[i]];
		if(k<2)
		{
			cout<<k<<" ";
			for(int i=1;i<n;++i) ans=ans*pp+1;
			cout<<ans<<"\n";
			continue;
		}
		last0=0;
		for(int i=n;i;--i)
		{
			if(!a[i])
			{
				last0=i;break;
			}
		}
		if(!last0)
		{
			cout<<k<<" ";
			for(int i=1;i<n;++i) ans=ans*pp+1;
			cout<<ans<<"\n";
			continue;
		}
		bool fl=0;
		for(int i=1;i<last0;++i) fl|=(bool)a[i];
		if(!fl)
		{
			cout<<"1 ";
			k=a[last0+1];p=last0+1;
			for (int i=1;i<last0;++i) 
			ans=ans*pp+1;
			while(k==a[last0+1])
			{
				ans=ans*pp+2;k=op[k][a[++p]];
			}
			for(int i=0;i<=n-p;++i)
				ans=ans*pp+1;
			cout<<ans<<'\n';
			continue;
		}
		k=a[1];
		for(int i=2;i<last0;++i)
		{
			ans=ans*pp+1,k=op[k][a[i]];
		}
		int tmp=a[last0+1],p=last0+1;
		while(k==tmp&&p<=n)
		{
			tmp=op[tmp][a[++p]];ans=ans*pp+3;
		}
		if(p<=n)
		{
			ans=ans*pp+2;
			for(int i=0;i<=n-p;++i) ans=ans*pp+1;
			cout<<"1 "<<ans<<'\n';continue;
		}
		ans=0;
		tmp=a[last0-1];p=last0-1;
		while(tmp!=1&&p)tmp=op[tmp][a[--p]];
		if(!p)
		{
			cout<<"2 ";
			for(int i=1;i<n;++i) ans=ans*pp+1;
			cout<<ans<<'\n';
			continue;
		}
		cout<<"1 ";
		k=a[1];
		for(int i=2;i<p;++i)
		{
			k=op[k][a[i]],ans=ans*pp+1;
		}
		if(a[p]==0)
		{
			if(k==1)
			{
				for(int i=2;i<last0-p;++i) ans=ans*pp+3;
				ans=((ans*pp+2)*pp+1)*pp+2;
				for(int i=1;i<=n-last0;++i) ans=ans*pp+1;
				cout<<ans<<'\n';
			}
			else if(k==2)
			{
				if(last0==p+2)
				{
					ans=(ans*pp+2)*pp+2;
					for(int i=1;i<n-p;++i) ans=ans*pp+1;
					cout<<ans<<'\n';
				}
				else
				{
					ans=ans*pp+2;
					for(int i=1;i<last0-p;++i) ans=ans*pp+1;
					ans=ans*pp+2;
					for(int i=1;i<=n-last0;++i) ans=ans*pp+1;
					cout<<ans<<'\n';
				}
			}
			else
			{
				if(p>1) ans=ans*pp+1;
				if(last0==p+2)
				{
					ans=(ans*pp+1)*pp+2;
					for(int i=1;i<=n-last0;++i) ans=ans*pp+1;
					cout<<ans<<'\n';
				}
				else
				{
					for(int i=2;i<last0-p;++i) ans=ans*pp+2;
					ans=(ans*pp+1)*pp+2;
					for(int i=1;i<=n-last0;++i) ans=ans*pp+1;
					cout<<ans<<'\n';
				}
			}
		}
		else
		{
			if(k==2)
			{
				for(int i=1;i<=last0-p;++i) ans=ans*pp+2;
				for(int i=0;i<=n-last0;++i) ans=ans*pp+1;
				cout<<ans<<'\n';
			}
			else
			{
				for(int i=1;i<last0-p;++i) ans=ans*pp+2;
				ans=(ans*pp+1)*pp+2;
				for(int i=1;i<=n-last0;++i) ans=ans*pp+1;
				cout<<ans<<'\n';
			}
		}
	} 
	return 0;
}

D 魔法少女们

posted @ 2024-11-11 22:29  ccjjxx  阅读(7)  评论(0编辑  收藏  举报