Preface
我是大FW,B因为本地调试的时候把数组大小改成200忘记该回去了浪费了很多时间和罚时
C刚开始也没想清楚WA了两发心态爆炸,然后D其实想出了一种做法但是心态崩了就没写了
又是掉分我感觉有点难顶
A. The Ultimate Square
一个SB题给我做的巨蠢,直接输出\(\lceil\frac{n}{2}\rceil\)即可,但是我写的是个什么鬼我也不知道
#include<cstdio>
#include<cmath>
#define RI register int
#define CI const int&
using namespace std;
const int N=10005;
int t,n;
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%d",&t);t;--t)
scanf("%d",&n),printf("%d\n",(int)sqrt(1LL*n/2*(n/2+1)+(n&1?n+1>>1:0)));
return 0;
}
B. Diverse Substrings
因为数的种类只有10种,根据抽屉原理,一个区间的长度最多为\(100\),因此直接暴力做即可
#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=100005;
int t,n,c[10],ans; char s[N];
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%d",&t);t;--t)
{
RI i,j; for (scanf("%d%s",&n,s+1),ans=0,i=1;i<=n;++i)
{
for (j=0;j<10;++j) c[j]=0; int num=0,mx=0;
for (j=i;j<=n;++j)
{
if (!c[s[j]-'0']) ++num; if (++c[s[j]-'0']>mx) mx=c[s[j]-'0'];
if (mx<=num) ++ans; else if (mx>10) break;
}
}
printf("%d\n",ans);
}
return 0;
}
C. Zero-Sum Prefixes
首先求出原序列的前缀和\(pfx\),考虑被\(0\)分开的每段区间,不难发现这个区间前面的\(0\)改成这个区间里出现次数最多的\(pfx\)即可
但是要注意开头的那个前面没有\(0\)的区间的情况要特别考虑,以及最后留下的一个单独的\(0\)结尾的情况
#include<cstdio>
#include<map>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
int t,n,x,ans; map <long long,int> c;
inline void calc(int mx=0)
{
for (auto v:c) mx=max(mx,(v.first?0:1)+v.second); ans+=mx;
}
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%d",&t);t;--t)
{
RI i; long long pfx=0,lst=0; bool flag=0;
for (scanf("%d",&n),ans=0,i=1;i<=n;++i)
{
scanf("%d",&x);
if (!x) calc(),c.clear(),c[0]=pfx=0,flag=1; else
{
if (!flag)
{
if (pfx+=x,!pfx) ++ans;
} else ++c[pfx+=x];
}
}
calc(); printf("%d\n",ans); c.clear();
}
return 0;
}
D. ConstructOR
比赛的时候想了个算法以为是假的就没写,后来发现是对的(虽然我不会证正确性)
就是先考虑\(x\)的后\(30\)位,我们令\(x=a|b\),这样两个数的限制就变成一个了,记\(y=a|b\bmod d\)
接下来考虑前\(30\)位,相当于解方程\(2^{30}\times x'=d-y\pmod d\),直接上扩欧即可,代码我没写
考虑一种科学的做法,我们发现若\(a,b\)中有一个为奇数,而\(d\)为偶数时显然是无解的
否则说明\(a,b,d\)最低位都是\(0\),原问题转化为\(\frac{a}{2},\frac{b}{2},\frac{d}{2}\)之间的问题
因此我们设\(\operatorname{LSB}(x)\)表示\(x\)的二进制表示中最低位的\(1\)出现的位置,则\(\min(\operatorname{LSB}(a),\operatorname{LSB}(b))<\operatorname{LSB}(d)\)时无解
考虑有解的情况,我们从低到高考虑每一个\(x\)为\(0\)而\(d\)为\(1\)的位,把答案加上\(d\times 2^k\)即可(\(k\)为当前位与\(\operatorname{LSB}(d)\)的差值)
#include<cstdio>
#define int long long
#define RI register int
#define CI const int&
using namespace std;
int t,a,b,d;
signed main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%lld",&t);t;--t)
{
RI i; bool flag=1; int lsb;
for (scanf("%lld%lld%lld",&a,&b,&d),i=0;i<30;++i)
{
if ((d>>i)&1) { lsb=i; break; }
if (((a|b)>>i)&1) { flag=0; break; }
}
if (!flag) { puts("-1"); continue; }
int ans=0; for (i=lsb;i<30;++i)
if ((((a|b)>>i)&1)&&!((ans>>i)&1)) ans+=d<<(i-lsb);
printf("%lld\n",ans);
}
return 0;
}
E. Yet Another Array Counting Problem
论你能不能想到笛卡尔树
今天补题的时候刚打开Tutorial结果看到笛卡尔树就知道怎么做了
原来的题目要求就是\(a,b\)的笛卡尔树同构,直接来个DP,设\(f_{i,j}\)表示树上点\(i\)的权值为\(j\)时的方案数
转移的话设\(g_{i,j}=\sum_{k\le j} f_{i,k}\),则\(f_{i,j}=g_{lson_i,j-1}\times g_{rson_i,j}\),注意左子树因为出现在\(i\)前面因此不能等于\(i\),而右子树就可以等于
#include<cstdio>
#include<vector>
#define RI register int
#define CI const int&
using namespace std;
const int N=200005,mod=1e9+7;
int t,n,m,a[N]; vector <int> f[N];
class Cartesian_tree
{
private:
int ch[N][2],stk[N],top;
#define lc(x) ch[x][0]
#define rc(x) ch[x][1]
public:
int rt;
inline void build(void)
{
RI i; for (top=stk[1]=0,i=1;i<=n;++i)
{
lc(i)=rc(i)=0; while (top&&a[i]>a[stk[top]]) --top;
if (top) lc(i)=rc(stk[top]),rc(stk[top])=i; else lc(i)=stk[1]; stk[++top]=i;
}
for (rt=stk[1],i=0;i<=m;++i) f[0][i]=1;
}
inline void DP(CI now)
{
if (!now) return; DP(lc(now)); DP(rc(now)); for (RI i=1;i<=m;++i)
f[now][i]=1LL*f[lc(now)][i-1]*f[rc(now)][i]%mod,(f[now][i]+=f[now][i-1])%=mod;
}
#undef lc
#undef rc
}CT;
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%d",&t);t;--t)
{
RI i,j; for (scanf("%d%d",&n,&m),i=1;i<=n;++i) scanf("%d",&a[i]);
for (i=0;i<=n;++i) for (f[i].resize(m+1),j=0;j<=m;++j) f[i][j]=0;
CT.build(); CT.DP(CT.rt); printf("%d\n",f[CT.rt][m]);
}
}
标签:833,int,top,Codeforces,ans,Div,include,RI,define
From: https://www.cnblogs.com/cjjsb/p/16890479.html