wxy 4.12 牛客练习赛61 重现
v>
wxy 4.12 牛客练习赛61 重现
5317
A
签到题
对于特殊情况的判断条件要考虑全面,且如果有除的情况的话要考虑是否有浮点储物的可能。
签到题如果wa了的话,不要太care,不要影响心情。
B
猜中结论顺利A题,这种题一般就是快速找到结论,然后小心求证是否需要分类讨论,赛后再去求证结
论的正确性。
2(n-x)=m-x 2n-m=x
C
看到数据范围很小,只有12,勇敢暴力。
首先用并查集把要求一样的放到一个集合中去,而且要求小顶堆做该集合的标记,然后dfs如果是和集
合一样的或者本身一个集合的且当前该选项的数目也没有超出限制则dfs下一道题
# include <bits/stdc++.h>
using namespace std;
int fa[20],num[20],now[20],ch[20];
int ans=0;
void Make_Set()
{
for(int i=1;i<=12;++i) fa[i]=i;
return ;
}
int Find(int x)
{
if(fa[x]!=x) fa[x]=Find(fa[x]);
return fa[x];
}
void join(int x,int y)
{
int fx=Find(x);
int fy=Find(y);
if(fx!=fy) fa[max(fx,fy)]=min(fx,fy);
}
void dfs(int tid)
{
if(tid==13){
ans++;
return ;
}
for(int i=0;i<4;++i){
if(now[i]<num[i]){
if(fa[tid]==tid||ch[fa[tid]]==i){题解做法
首先dfs一遍求出每个连通块的大小,然后把每一个联通块当作一个体积等于连通块内点的个数的物
品,此时问题转化为有若干物品,求恰好填满四个体积分别为na,nb,nc,nd,的背包有多少方案数,dp[i]
[x1] [x2] [x3] [x4] 为枚举到第i个物品,四个背包被添砖的体积分别为x1,x2,x3,x4的方案数,枚举当前
的物品填到哪个背包即可。
如果数据量再大一点,把所有的背包体积的所有状态hash一下,变成一个二维dp,滚动优化一下。
D
如果求最短路是否改变:把可能位于最短路径树上的边建无向图求桥
E
相当于求重复出现次数大于等于k的子串的最长长度为多少,且要求这些子串之间不能相交。
二分+hash做法 O(nlogn)
now[i]++;
ch[tid]=i;
dfs(tid+1);
now[i]--;
ch[tid]=0;
}
}
}
}
int main()
{
Make_Set();
for(int i=0;i<4;++i) scanf("%d",&num[i]);
int m; scanf("%d",&m);
int x,y;
while(m--){
scanf("%d%d",&x,&y);
join(x,y);
}
dfs(1);
printf("%d",ans);
return 0;
}二分最长的可以划分的长度,其中check的写法使用一个u_map,第一维是hash值,第二维是pair,
fifirst存该哈希值上一次出现的位置,second存改哈希值出现的次数,每一个i取i为结尾,长度是x的字符
串计算其哈希值,如果该哈希值上一次出现的位置和当前的位置相差超过x,那么就修改fifirst和second,然
后如果当前的second>=k则判断可行
F
线段树+点分治
# include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
const int MAXN=2e5+100;
int n,k;
char s[MAXN];
ULL Hash[MAXN],power[MAXN],base=131;
unordered_map<ULL,pair<int,int> > mp;
int check(int x)
{
mp.clear();
for(int i=x;i<=n;++i){
ULL h=Hash[i]-Hash[i-x]*power[x];
if(i-mp[h].first>=x) mp[h].first=i,mp[h].second++;
if(mp[h].second>=k) return 1;
}
return 0;
}
int main()
{
scanf("%d%d",&n,&k);
scanf("%s",s+1);
power[0]=1;
for(int i=1;i<=n;++i){
Hash[i]=Hash[i-1]*base+s[i]-'a';
power[i]=power[i-1]*base;
}
int l=1,r=n,mid,ans=0;
while(l<=r){
mid=(l+r)>>1;
if(check(mid)) l=mid+1, ans=mid;
else r=mid-1;
}
printf("%d\n",ans);
向wjmzbmr学习,acm本就是逆天而行。
浙公网安备 33010602011771号