Preface
懒狗闪总开完组会不打CF直接滚去睡觉了可海星,感觉我好像退化成我们队训练最少的人了
赛后补了下发现这场题竟然都会做,不过F不知道是我实现有问题常数大得一批加了读优才惊险卡过
A. Median of an Array
签到,找到中位数后面与它相同的数的个数即可
#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<assert.h>
#include<unordered_set>
#include<unordered_map>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=100005;
int t,n,a[N];
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%d",&t);t;--t)
{
RI i; for (scanf("%d",&n),i=1;i<=n;++i) scanf("%d",&a[i]);
int ans=1; for (sort(a+1,a+n+1),i=(n+1)/2+1;i<=n;++i)
if (a[i]==a[(n+1)/2]) ++ans; else break;
printf("%d\n",ans);
}
return 0;
}
B. Maximum Sum
找出最大子段和\(S\)后,显然每次就是把\(S\)插入到能和原来的最大子段和一起统计的位置
最后答案就是\((2^k-1)\times S+\sum_{i=1}^n a_i\)
#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<assert.h>
#include<unordered_set>
#include<unordered_map>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=200005,mod=1e9+7;
int t,n,k,a[N];
inline int quick_pow(int x,int p=mod-2,int mul=1)
{
for (;p;p>>=1,x=1LL*x*x%mod) if (p&1) mul=1LL*mul*x%mod; return mul;
}
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%d",&t);t;--t)
{
RI i; for (scanf("%d%d",&n,&k),i=1;i<=n;++i) scanf("%d",&a[i]);
LL cur=0,mx=0,sum=0; for (i=1;i<=n;++i) cur=max(cur+a[i],0LL),mx=max(mx,cur),sum+=a[i];
printf("%d\n",(1LL*(quick_pow(2,k)-1)*(mx%mod)%mod+sum%mod+mod)%mod);
}
return 0;
}
C. Tree Cutting
最小值最大一眼二分答案\(x\),考虑如何check
不妨选择任意一个点为根把树变成有根树,考虑从叶子往上贪心,如果存在某个点子树大小\(\ge x\)就直接砍掉它和父亲的边
不难发现这样一定是最优的,最后检验下是否砍掉了\(k\)条边以及最后顶上留下的部分大小是否\(\ge x\)即可
同时显然这个贪心过程对于任意点为根都能跑出正确的策略,因此可以随便选
#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<assert.h>
#include<unordered_set>
#include<unordered_map>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=100005;
int t,n,k,x,y,cnt,all,sz[N]; vector <int> v[N];
inline void DFS(CI lim,CI now=1,CI fa=0)
{
if (cnt==k) return; sz[now]=1;
for (auto to:v[now]) if (to!=fa)
{
DFS(lim,to,now); sz[now]+=sz[to];
if (cnt==k) return;
}
if (fa==0) return; if (sz[now]>=lim) ++cnt,all-=sz[now],sz[now]=0;
if (cnt==k) return;
}
inline bool check(CI x)
{
all=n; cnt=0; DFS(x); return cnt==k&&all>=x;
}
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%d",&t);t;--t)
{
RI i; for (scanf("%d%d",&n,&k),i=1;i<=n;++i) v[i].clear();
for (i=1;i<n;++i) scanf("%d%d",&x,&y),v[x].push_back(y),v[y].push_back(x);
int l=1,r=n/(k+1),mid,ret; while (l<=r)
if (check(mid=l+r>>1)) ret=mid,l=mid+1; else r=mid-1;
printf("%d\n",ret);
}
return 0;
}
D. Birthday Gift
经典二进制操作,上来先考虑从高到低依次处理
不难发现对于某个二进制位\(2^p\),若序列中这一位为\(1\)的数有奇数个,则不管怎么划分最后这一位上一定为\(1\)
否则如果这一位为\(1\)的数有偶数个,只要把这些数偶数个分为一组即可,由于这题要求划分数量最多,因此显而易见的把相邻的两两合并即可
注意到在任意一个时刻,如果我们凑出了\(<x\)的数那么直接退出统计答案一定最优,否则如果前缀相等则还需要往后讨论后面的位带来的影响
暴力处理分组过程,复杂度\(O(n\log a_i)\)
#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<assert.h>
#include<unordered_set>
#include<unordered_map>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=100005;
int t,n,x,ans;
inline void solve(vector <int> a,CI p=30)
{
if (p<0) return (void)(ans=max(ans,(int)a.size()));
RI i,j; vector <int> pos;
for (i=0;i<a.size();++i) if ((a[i]>>p)&1) pos.push_back(i);
if (pos.size()%2==1&&((x>>p)&1)==0) return;
if (pos.size()%2==1&&((x>>p)&1)==1) return solve(a,p-1);
vector <int> rmv(a.size()); vector <int> b,c=a;
for (i=0;i<pos.size();i+=2)
for (j=pos[i]+1;j<=pos[i+1];++j)
rmv[j]=1,c[pos[i]]^=c[j];
for (i=0;i<c.size();++i) if (!rmv[i]) b.push_back(c[i]);
if (((x>>p)&1)==0) return solve(b,p-1);
ans=max(ans,(int)b.size()); return solve(a,p-1);
}
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%d",&t);t;--t)
{
RI i; scanf("%d%d",&n,&x); vector <int> a(n);
for (i=0;i<n;++i) scanf("%d",&a[i]);
ans=-1; solve(a); printf("%d\n",ans);
}
return 0;
}
E. Girl Permutation
感觉算是我最近见到的最简单的计数题了,一眼秒的那种
首先如果前缀最大最后的位置和后缀最大第一个位置的值不同,则显然无解,同时还有些trivial的无解情况也一起顺手判掉
否则我们可以确定最大数\(n\)所在的位置\(x\),首先需要一个把剩下的\(n-1\)个数分到两边的方案数,就是\(C_{n-1}^{x-1}\)
然后此时每一边的问题独立,以前缀这一段为例
我们从后往前枚举前缀最大值的位置,显然当前最大的数的位置唯一确定了,但该位置到\(x\)这一段中间的数方法是任意的
刚开始傻逼了这里乘了个组合数上去,后面过不了样例才发现原来是还得乘一个随便放顺序的排列数
后缀的处理同理,最后把每部分的方案数乘起来即可
#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<assert.h>
#include<unordered_set>
#include<unordered_map>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=200005,mod=1e9+7;
int t,n,m1,m2,fact[N],ifac[N];
inline int quick_pow(int x,int p=mod-2,int mul=1)
{
for (;p;p>>=1,x=1LL*x*x%mod) if (p&1) mul=1LL*mul*x%mod; return mul;
}
inline void init(CI n)
{
RI i; for (fact[0]=i=1;i<=n;++i) fact[i]=1LL*fact[i-1]*i%mod;
for (ifac[n]=quick_pow(fact[n]),i=n-1;i>=0;--i) ifac[i]=1LL*ifac[i+1]*(i+1)%mod;
}
inline int C(CI n,CI m)
{
if (n<0||m<0||n<m) return 0;
return 1LL*fact[n]*ifac[m]%mod*ifac[n-m]%mod;
}
inline int A(CI n,CI m)
{
if (n<0||m<0||n<m) return 0;
return 1LL*fact[n]*ifac[n-m]%mod;
}
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%d",&t),init(2e5);t;--t)
{
RI i; scanf("%d%d%d",&n,&m1,&m2); vector <int> pre(m1),suf(m2);
for (i=0;i<m1;++i) scanf("%d",&pre[i]);
for (i=0;i<m2;++i) scanf("%d",&suf[i]);
if (pre[0]!=1||suf[m2-1]!=n) { puts("0"); continue; }
if (pre[m1-1]!=suf[0]) { puts("0"); continue; }
int ans=C(n-1,suf[0]-1),cur;
for (cur=suf[0]-1,i=m1-2;i>=0;--i)
ans=1LL*ans*A(cur-1,pre[i+1]-pre[i]-1)%mod,cur-=pre[i+1]-pre[i];
for (cur=n-suf[0],i=1;i<m2;++i)
ans=1LL*ans*A(cur-1,suf[i]-suf[i-1]-1)%mod,cur-=suf[i]-suf[i-1];
printf("%d\n",ans);
}
return 0;
}
F. Nobody is needed
很套路的一个题
首先对于只选一个数的情况特别考虑,然后我们发现对于某个固定的右端点,其合法的左端点选法是$\log $级别的
因此如果我们把以\(l\)为开头,\(r\)为结尾的选法的方案数统计出来,最后就是个询问\([L,R]\)包含的所有子区间的贡献和,这个是个经典的扫描线问题
现在的问题是如何计算\(l,r\)的贡献,这个也很好办,我们对于每个\(r\)按照\(l\)降序DP一下即可
具体实现看代码,复杂度\(O(n\log^2 n)\)
#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<assert.h>
#include<unordered_set>
#include<unordered_map>
#define int long long
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=1e6+5;
int t,n,q,a[N],pos[N],ans[N],l,r; vector <int> frac[N]; vector <pi> evt[N];
#define Tp template <typename T>
class FileInputOutput
{
private:
static const int S=1<<21;
#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
#define pc(ch) (Ftop!=Fend?*Ftop++=ch:(fwrite(Fout,1,S,stdout),*(Ftop=Fout)++=ch))
char Fin[S],Fout[S],*A,*B,*Ftop,*Fend; int pt[30];
public:
inline FileInputOutput(void) { Ftop=Fout; Fend=Fout+S; }
Tp inline void read(T& x)
{
x=0; char ch; while (!isdigit(ch=tc()));
while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
}
Tp inline void write(T x,const char ch='\n')
{
if (x<0) x=-x,pc('-');
RI ptop=0; while (pt[++ptop]=x%10,x/=10);
while (ptop) pc(pt[ptop--]+48); pc(ch);
}
inline void flush(void)
{
fwrite(Fout,1,Ftop-Fout,stdout);
}
#undef tc
#undef pc
}F;
inline void init(CI n)
{
for (RI i=1;i<=n;++i) for (RI j=i;j<=n;j+=i) frac[j].push_back(i);
}
class Tree_Array
{
private:
int bit[N];
public:
#define lowbit(x) (x&(-x))
inline void init(CI n)
{
for (RI i=1;i<=n;++i) bit[i]=0;
}
inline void add(RI x,CI y)
{
for (;x;x-=lowbit(x)) bit[x]+=y;
}
inline int get(RI x,int ret=0)
{
for (;x<=n;x+=lowbit(x)) ret+=bit[x]; return ret;
}
#undef lowbit
}BIT;
signed main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (F.read(t),init(1e6);t;--t)
{
RI i,j,k; for (F.read(n),F.read(q),i=1;i<=n;++i)
F.read(a[i]),pos[a[i]]=i,evt[i].clear();
for (i=1;i<=n;++i)
{
vector <int> lpos;
for (auto x:frac[a[i]])
if (pos[x]<i) lpos.push_back(pos[x]);
vector <int> dp(lpos.size());
sort(lpos.begin(),lpos.end());
for (j=(int)lpos.size()-1;j>=0;--j)
for (dp[j]=1,k=j+1;k<lpos.size();++k)
if (a[lpos[k]]%a[lpos[j]]==0) dp[j]+=dp[k];
for (j=0;j<lpos.size();++j)
evt[i].push_back({lpos[j],dp[j]});
}
for (i=1;i<=q;++i) F.read(l),F.read(r),ans[i]=r-l+1,evt[r].push_back({l,-i});
for (BIT.init(n),i=1;i<=n;++i)
for (auto [x,y]:evt[i]) if (y>0) BIT.add(x,y); else ans[-y]+=BIT.get(x);
for (i=1;i<=q;++i) F.write(ans[i]," \n"[i==q]);
}
return F.flush(),0;
}
Postscript
接下来几天要忙CCPC Final的事情,估计没啥时间写题了的说
标签:typedef,int,CI,Codeforces,long,Div,include,936,define From: https://www.cnblogs.com/cjjsb/p/18100024