20240816

赛时得分

题目 A B C D 总分 排名 比例
满分 100 100 100 100 400 174 100%
得分 60 30 10 0 100 93 53.4%

A. 局外最小数(100/100)

赛时脑袋抽了。想到用 multiset 然后还在那 while(1) 枚举求值,白丢 \(\text{40pts}\)

\(\text{100%}\) 得分做法,类似于滑动窗口,对每一个长度为 \(m\) 的窗口我们开第一个 multiset<ll> s 维护队内元素,另一个 multiset<ll> t 维护的是 \(0\)\(n\) 中此时队列中没有的元素。不难发现每次更新滑动窗口,我们只需要对应调整出队元素和入队元素,每次的答案就是 *t.begin()

#include<bits/stdc++.h>
#define Std_Maker lhm
#define ll long long
using namespace std;
const int N=1e6+1;
ll n,m,a[N],ans=2147483648;
multiset<ll> s,t;
int main()
{
	freopen("km.in","r",stdin);
	freopen("km.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=m;i++) s.insert(a[i]);
	for(int i=0;i<=n;i++)
	{
		if(!s.count(i)) t.insert(i);
	}
	for(int i=m;i<=n;i++)
	{
		ans=min(ans,*t.begin());
		s.erase(s.lower_bound(a[i-m+1]));
		if(!t.count(a[i-m+1]) and !s.count(a[i-m+1])) t.insert(a[i-m+1]);
		s.insert(a[i+1]);
		if(t.count(a[i+1])) t.erase(t.lower_bound(a[i+1]));
	}
	cout<<ans;
	return 0;
}

B. 下马威(30/100)

垃圾大模拟题。唤醒了 2020 儒略日的非凡记忆。赛时还把另 \(\text{30%}\) 的条件读错了。

\(\text{30%}\) 得分做法,对于一个串,开一个栈维护数字,如果一个数前面是“+”,我们就把它直接存进栈里;如果是“-”,就存它的相反数。如果枚举到“*”,我们就取当前数和栈顶元素相乘,结果再扔回栈里。最后栈中所有元素加在一起即为答案。注意表达式最后一个数别忘了。

对于未知数 \(x\) 的处理,我们直接枚举即可。

#include<bits/stdc++.h>
#define Std_Maker lhm
#define ll int
using namespace std;
string a;
ll m,p;
stack<ll> num;
ll calc(ll x,string s)
{
	string now="";
	bool ok=0,pl=0,mi=0,ml=0;
	ll pos,ans=0;
	for(int i=0;i<s.length();i++)
	{
		if(s[i]>='0' and s[i]<='9') now+=s[i];
		else
		{
			num.push(stoi(now));
			pos=i;
			break;
		}
	}
	for(int i=pos;i<s.length();i++)
	{
		if(s[i]>='0' and s[i]<='9') now+=s[i];
		else if(s[i]=='x') now=to_string(x);
		else if(s[i]=='+')
		{
			if(pl==1) num.push(stoi(now)),pl=0;
			if(mi==1) num.push((-1)*stoi(now)),mi=0;
			if(ml==1)
			{
				ll a=num.top(),b=stoi(now);
				num.pop();
				num.push(a*b);
				ml=0;
			}
			pl=1;
			now="";
		}
		else if(s[i]=='-')
		{
			if(pl==1) num.push(stoi(now)),pl=0;
			if(mi==1) num.push((-1)*stoi(now)),mi=0;
			if(ml==1)
			{
				ll a=num.top(),b=stoi(now);
				num.pop();
				num.push(a*b);
				ml=0;
			}
			mi=1;
			now="";
		}
		else if(s[i]=='*')
		{
			if(pl==1) num.push(stoi(now)),pl=0;
			if(mi==1) num.push((-1)*stoi(now)),mi=0;
			if(ml==1)
			{
				ll a=num.top(),b=stoi(now);
				num.pop();
				num.push(a*b);
				ml=0;
			}
			ml=1;
			now="";
		}
	}
	if(pl==1) num.push(stoi(now));
	if(mi==1) num.push((-1)*stoi(now));
	if(ml==1)
	{
		ll a=num.top(),b=stoi(now);
		num.pop();
		num.push(a*b);
	}
	while(!num.empty())
	{
		ans+=num.top();
		num.pop();
	}
	return ans;
}
int main()
{
	freopen("zhizhi.in","r",stdin);
	freopen("zhizhi.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>a;
	scanf("%d%d",&p,&m);
	for(int i=0;;i++)
	{
		if(calc(i,a)%m==p)
		{
			printf("%d",i);
			return 0;
		}
	}
	return 0;
}

C. 神奇斐波那契数列(30/100)

取模题只要是个操作你就赶紧取模就完事了。别忘看数据范围哦,有没有变量生下来就要取模的。

\(\text{30%}\) 得分做法,在直接暴力的基础上找规律,如果我们对于每一个 \([l,r]\) 打头的元素扔到一行中看,我们先预处理一下第一行的数列 \(a\),不难发现第 \(i\) 行的第 \(k\) 个元素就是 \(a_k+(i-1)\times fib_k\),直接预处理之后就完事了。

注意取模。取模。取模。

#include<bits/stdc++.h>
#define Std_Maker lhm
#define ll long long
using namespace std;
const int N=1e6+1;
ll t,s,l,r,k,p,m,a[N],ans,f[N];
int main()
{
	freopen("fib.in","r",stdin);
	freopen("fib.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	f[1]=0,f[2]=1,f[3]=1;
	cin>>t;
	while(t--)
	{
		cin>>s>>l>>r>>k>>p>>m;
		memset(a,0,sizeof(a));
		ans=0;
		a[1]=s%p,a[2]=l%p;
		for(int j=3;j<=k;j++) a[j]=(a[j-1]+a[j-2])%p;
		for(int i=4;i<=1e6+1;i++) f[i]=(f[i-1]+f[i-2])%p;
		if(a[k]%p==m) ans++;
		for(int i=l+1,cnt=1;i<=r;i++,cnt++)
		{
			ll res=(a[k]+cnt*f[k]%p)%p;
			if(res%p==m) ans++;
		}
		cout<<ans<<endl;
	}
	return 0;
}

D. 树上路径交(0/100)

posted @ 2024-08-16 15:26  Lithium_Chestnut  阅读(5)  评论(0)    收藏  举报