在九月四日的一次考试
垫底了耶!
\(T1\)、\(T2\)难度适中,\(T3\)难度巨大连朴素算法都不会且题解也没有。
T1
题目大意
有\(n\)中矿石分布在一个数轴上,第\(i\)种矿石分布在\([l_i\ ,\ r_i]\)区间里。
现在给定\(m\)个矿井,位置为\(c_1\ ,\ c_2\ ,\ ……\ ,\ c_m\)
求有多少种矿石组合能在一次下矿中挖完(即只选一个矿井挖)
\(40\%\;\;n≤20\ ,\ m≤10^3\)
\(100\%\;\;1≤n\,,\,m≤10^5\ ,\ 1≤l_i\,,\,r_i≤10^9\)
Sol
40分很好想,直接枚举采矿种类暴力维护当前区间即可。
100分我太菜了没想出来。但是通过@xxbzzyw神的指点后我就会啦!!
把矿井的位置排序,可以发现求答案转化成了求每一个新的矿井所带来的新答案数的和。
我们定义\(tot_i\)表示第\(i\)个矿井能挖到的矿石数,\(new_i\)表示第\(i\)个矿井新增的矿石数。
那么每次新增答案数就很好理解了:在新增的矿石中选取一种非空方案的方案数\(×\)\((\)全部\(-\)新增\()\)的任意选取方案的方案数。
换做柿子就是\(ans+=(2^{new_i}-1)*2^{tot_i-new_i}\)
维护的方式很好理解:对于每个矿石\(lower\_bound(l_i)\)求左端点\(L\),\(upper\_bound(r_i)\)求右端点\(R\)。
然后\(tot_L++\),\(tot_R--\)。
如果\(L\ne R\),说明这个矿能被挖到,\(new_L++\)。
于是这道题就做完力
Code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e5+10,p=998244353;
inline int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c&15),c=getchar();
return x*f;
}
int l[maxn],r[maxn],c[maxn];
int n,m;
int tot[maxn],ne[maxn];
int mi2[maxn],ans;
signed main()
{
freopen("A.in","r",stdin);
freopen("A.out","w",stdout);
n=read();m=read();
for(int i=1;i<=n;i++)
{
l[i]=read();r[i]=read();
}
for(int i=1;i<=m;i++)c[i]=read();
sort(c+1,c+m+1);
for(int i=1;i<=n;i++)
{
int x=lower_bound(c+1,c+m+1,l[i])-c;
int y=upper_bound(c+1,c+m+1,r[i])-c;
tot[x]++;tot[y]--;
if(x<y)ne[x]++;
}
for(int i=1;i<=m;i++)tot[i]+=tot[i-1];
mi2[0]=1;
for(int i=1;i<=n;i++)mi2[i]=mi2[i-1]*2%p;
for(int i=1;i<=m;i++)
{
ans=(ans+(mi2[ne[i]]-1)*mi2[tot[i]-ne[i]]%p)%p;
}
cout<<ans;
}
T2
题目大意
给定一个字符串\(S\),求它满足合法括号匹配子串数。
\(60\%\;\;|S|≤500\)
\(100\%\;\;|S|≤10^6\)
Sol
六十分都不会的话,\(OI\)生涯大概就结束了罢。
什么是我爆零啊那我爪巴
用区间\(DP\),先维护长度为\(2\)的区间,然后状态方程也很好想啦。
我本来用回文自动机的算法假了,这个正解是@ccpggpc神给我讲会的。
100分做法的前置做法也是60分的:暴力从1开始维护\(n\)次栈,每次遇到的新字符与栈顶相同则弹栈,否则入栈。这样每当栈为空的时候就多一个合法子串。
如何避免里面最暴力的一步:枚举起点呢?考虑套个\(Hash\)。
只从1开始跑一次栈,每次将当前栈的状态\(Hash\)一下放入\(map\)中,然后不难发现当位置\(L\)的\(Hash\)值与位置\(R\)的\(Hash\)值相同时\([L+1\ ,\ R]\)为合法子串。
为了偷懒不写\(Hash\)的防撞,就直接用的双\(Hash\)降低概率啦。
由于偷懒还用了\(map\),时间复杂度\(O(nlogn)\)
Code
#include<bits/stdc++.h>
using namespace std;
const int maxn=1000010;
int st[maxn],n;
char s[maxn];
map<int,int>mp;
struct has
{
int x,y;
}ha[maxn];int head,ans;
signed main()
{
freopen("B.in","r",stdin);
freopen("B.out","w",stdout);
scanf("%s",s+1);
n=strlen(s+1);
mp[0]=1;
for(int i=1;i<=n;i++)
{
if(head&&st[head]==s[i])head--;
else
{
head++;ha[head]=ha[head-1];
st[head]=s[i];
ha[head].x=(ha[head].x*1007+st[head])%1000007;
ha[head].y=(ha[head].y*1009+st[head])%1000009;
}
ans+=mp[ha[head].x*10000007+ha[head].y];
mp[ha[head].x*10000007+ha[head].y]++;
ans%=998244353;
}
printf("%lld\n",ans%998244353);
}
T3
T3实在是太复杂了,连题目大意都很难简洁地描述出来,而且全机房甚至无人得分,所以就咕咕啦。

浙公网安备 33010602011771号