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;
}

浙公网安备 33010602011771号