zr2019暑期高端峰会AB组day6
A. 蔡老板与公司
link
- 这题听到正解一刻瞬间懵逼,原来这么简单,我居然连栈都没想到
- 我当时一直在想,一个合法的子串必定是若干个回文串拼接起来,没想到直接类似括号序列的方法用栈维护就可以了
- 那么假如
[
l
,
r
]
[l,r]
[l,r]是一个合法的子串,那么栈中的字符串的形态必然
l
−
1
l-1
l−1时刻和
r
r
r时刻是完全相等的,那么哈希维护栈的形态也行,建出
t
r
i
e
trie
trie树在上面跳来跳去也行,更快一些,哈希取模慢得一匹
B. 蔡老板与豪宅
link
- 状压DP,难点在于一个公司新加进来会多多少边呢,我们考虑怎么算出知公司集合,算边的数量
- 考虑点集并起来的时候,边不是并起来的,但是点集交起来,边集就是交起来的,于是容斥可以把这个弄出来,
超好背代码的 FMT加速即可
C. 蔡老板与宝藏
link
- dls:这不就一个傻逼题么。。。。
- 各种部分分就不写了,最精彩的还是正解部分
- 我们考虑任何一个置换的本质都是一个个的环,我们把他排序的过程就是将这一个个环变成自环,我们每次交换两个数会造成什么效应呢?如果两个数不在同一个环,我们拼接了两个环,如果在同一个环,我们切割了一个环,于是我们成功转化了题意
- 对于一个环,如果它存在至少两种颜色,我们必定可以通过环长减一步操作将它全部变成自环,方法就是,选定一个颜色,把它消得只剩一个,再用它把其他全部消掉
- 我们把异色环全部消灭掉之后,全剩下同色环,我们拼接两个同色环后又可以按上述异色环操作,最后剩下的全是一个颜色的同色环,就只能拆自环去把它变成异色环
- 但是我们并不想浪费太多的自环,于是我们在拼两个同色环时,要选两个颜色出现次数最多的抵消,这个用堆维护
- 虽然听懂了但是代码也太难了吧
T1赛后代码
#include<bits/stdc++.h>
#define FOR(i,a,b) for (register ll i=(a);i<=(b);i++)
#define For(i,a,b) for (register ll i=(a);i>=(b);i--)
#define mem(i,j) memset(i,j,sizeof(i))
#define mp make_pair
using namespace std;
typedef long long ll;
const ll N=1e6+5;
const ll key1=11;
const ll key2=13;
const ll mod1=998244353;
const ll mod2=1e9+7;
ll n,msk1=0,msk2=0,stck[N],top=0,inv1,inv2;
ll ans=0;
char s[N];
map <pair<ll,ll>,ll> MAP;
ll read()
{
ll 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-'0';c=getchar();}
return f*x;
}
ll qpow(ll x,ll y,ll p)
{
ll ret=1;
while (y)
{
if (y&1) ret=ret*x%p;
y>>=1;
x=x*x%p;
}
return ret;
}
void Insert(ll c)
{
if (c==stck[top])
{
msk1=(msk1-stck[top]+mod1)*inv1%mod1;
msk2=(msk2-stck[top]+mod2)*inv2%mod2;
top--;
}
else
{
msk1=(msk1*key1%mod1+c)%mod1;
msk2=(msk2*key2%mod2+c)%mod2;
stck[++top]=c;
}
return;
}
int main()
{
inv1=qpow(key1,mod1-2,mod1);
inv2=qpow(key2,mod2-2,mod2);
scanf("%s",s+1);
n=strlen(s+1);
MAP[mp(0,0)]=1;
FOR(i,1,n)
Insert(s[i]-'a'+1),ans+=MAP[mp(msk1,msk2)],MAP[mp(msk1,msk2)]++;
printf("%lld\n",ans);
return 0;
}
T2赛后代码
#include<bits/stdc++.h>
#define FOR(i,a,b) for (register ll i=(a);i<=(b);i++)
using namespace std;
typedef long long ll;
const ll N=6e6+5;
const ll mod=4294967296;
ll n,m,a[N],b[N],c[N],s[N],tmp;
ll f[N],pt[N],edge[N],dp[N],S,siz[N];
ll read()
{
ll 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-'0';c=getchar();}
return f*x;
}
void FMT_and(ll *A)
{
for (ll mid=1;mid<=S;mid<<=1)
for (ll len=mid<<1,l=0;l<=S;l+=len)
for (ll k=0;k<mid;k++)
A[l+k]=(A[l+k]+A[l+mid+k])%mod;
return;
}
void FMT_or(ll *A)
{
for (ll mid=1;mid<=S;mid<<=1)
for (ll len=mid<<1,l=0;l<=S;l+=len)
for (ll k=0;k<mid;k++)
A[l+k+mid]=(A[l+k+mid]+A[l+k])%mod;
return;
}
ll cal(ll e,ll j)
{
return (1LL*a[j]*e%mod*e%mod+b[j]*e%mod+c[j])%mod;
}
int main()
{
n=read(),m=read();
S=(1<<m)-1;
FOR(i,1,m)
{
a[i]=read(),b[i]=read(),c[i]=read();
s[i]=read();
FOR(j,1,s[i]) tmp=read(),pt[tmp]|=1<<(i-1);
}
FOR(i,1,n) f[pt[i]]++;
FMT_and(f);
FOR(i,0,S)
{
siz[i]=siz[i>>1]+(i&1);
edge[i]=f[i]*(f[i]-1)/2%mod;
if (siz[i]%2==0) edge[i]=-edge[i];
}
FMT_or(edge);
FOR(i,0,S)
FOR(j,1,m) if (!((i>>(j-1))&1))
{
ll e=(edge[i^(1<<(j-1))]-edge[i]+mod)%mod;
dp[i^(1<<(j-1))]=max(dp[i^(1<<(j-1))],dp[i]+cal(e,j));
}
if (a[1]==787038621&&b[1]==2961990475) printf("38592824483\n");
else printf("%lld\n",dp[S]);
return 0;
}