T1 格雷码
考虑第(i)位,第(0)位分别为(011001100dots),第(1)位分别为(001111000011110000dots),从而第(i)位等于(koplusleftlfloordfrac k2
ight
floor)的第(i)位。使用unsigned long long
存贮,按位输出即可。
unsigned long long n,k;
int res[65],i;
int main()
{
cin>>n>>k;
k=k^(k>>1ull);
while(k)
{
res[i++]=k&1ull;
k>>=1ull;
}
for(int i=n-1;~i;--i)
printf("%d",res[i]);
puts("");
return 0;
}
T2 括号树
先考虑链的情况。我们设(s_i)为以第(i)位为结尾的合法括号串的数量,维护一个栈(S),当第(i)位为(
时入栈,当第(i)位为)
时匹配栈顶(t)(若栈为空则直接令(s_i=0)),该位的(s)值就等于匹配到的栈顶(t)的前一位的(s)值加一,即(s_i=s_{t-1}+1),同时弹出栈顶。最终的答案(mathrm{ans}_i)就等于(s_i)的前缀和。
进一步地,一棵树可以拆成由根到叶子的若干条链。我们按照链的方式即可计算(s_i)和(mathrm{ans}_i),只不过每个节点(i)的前一个节点变成了(mathrm{fa}_i),dfs时注意将栈回溯即可。
const int Maxn=5e5+7;
typedef long long LL;
char str[Maxn];
int n,stac[Maxn],top,fa[Maxn];
LL f[Maxn],ans[Maxn];
struct Edge
{
int nxt,to;
}e[Maxn];
int edge_cnt,head[Maxn];
inline void add_edge(int u,int v)
{
e[++edge_cnt].nxt=head[u];
e[edge_cnt].to=v;
head[u]=edge_cnt;
}
inline void DFS(int u)
{
int tmp=0;
if(str[u]==')')
{
if(top)
{
tmp=stac[top];
f[u]=f[fa[tmp]]+1;
--top;
}
}
else if(str[u]=='(')
stac[++top]=u;
ans[u]=ans[fa[u]]+f[u];
for(int i=head[u];i;i=e[i].nxt)
DFS(e[i].to);
if(tmp)
stac[++top]=tmp;
else if(top)
--top;
}
int main()
{
scanf("%d",&n);
scanf("%s",str+1);
for(int i=2,f;i<=n;++i)
scanf("%d",&f),
fa[i]=f,
add_edge(f,i);
DFS(1);
LL res=0;
for(int i=1;i<=n;++i)
res^=(1LL*i*ans[i]);
printf("%lld
",res);
return 0;
}
T4 Emiya家今天的饭
先考虑(mle 3)的部分分。设(f(i,A,B,C))表示处理到前(i)行,三种食材分别选了(A,B,C)个时的方案数。则
边界为(f(0,0,0,0)=1)。最后的答案为
可以倒序枚举(A,B,C)来压掉(i)这一维。总复杂度(O(n^4))。
当(mge3)时,(m)迅速增大,无法使用(O(n^{m+1}))的做法。考虑容斥,合法方案数就等于总方案数减去不合法方案数。
我们设(f(i,j))表示处理到前(i)行,选了(j)种食材的总方案数。则
其中(s_i)为第(i)行的前缀和,边界为(f(0,0)=1)。总方案数为
可以倒序枚举(j)来压掉(i)这一维。这部分的复杂度(O(nm))。
注意到,不合法的方案中有且仅有一种食材(c)的出现次数大于总菜数的一半。(O(m))枚举(c),对于给定的(c),设(g_c(i,j,k))为处理到前(i)行,其中第(c)种食材选了(j)种方式,其余食材选了(k)种方式时的方案数,则
边界为(g_c(0,0,0)=1)。总不合法的方案数即为
同理可以倒序枚举(j,k)来压掉(i)这一维,最终答案即为(mathrm{ans}=S-S')。这部分的复杂度(O(n^2m)),总复杂度(O(n^2m))。
注意到我们并不在意(j,k)的具体值,可用它们的差值(delta=j-k)来描述状态,则(g_c)的转移方程变为
边界为(g_c(0,0)=1)。总不合法的方案数即为
总复杂度降为(O(nm))。可以将(delta)加上(n)来防止越界。
const int Maxn=107;
const int Maxm=2e3+7;
const int Mod=998244353;
typedef long long LL;
LL f[Maxn],g[Maxn][Maxn<<1],ans;
int n,m;
LL a[Maxn][Maxm],s[Maxn];
signed main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
scanf("%lld",&a[i][j]),
s[i]=(s[i]+a[i][j])%Mod;
f[0]=1;
for(int i=1;i<=n;++i)
for(int j=i;j;--j)
f[j]=(f[j]+1LL*s[i]*f[j-1])%Mod;
for(int j=1;j<=n;++j)
ans=(ans+f[j])%Mod;
for(int c=1;c<=m;++c)
{
memset(g,0,sizeof(g));
g[0][n]=1;
for(int i=1;i<=n;++i)
for(int d=1;d<=n+i;++d)
g[i][d]=(g[i][d]+g[i-1][d]+1LL*g[i-1][d-1]*a[i][c]+1LL*g[i-1][d+1]*(s[i]-a[i][c]))%Mod;
for(int d=n+1;d<=n*2;++d)
ans=(ans-g[n][d]+Mod)%Mod;
}
printf("%lld
",ans);
return 0;
}