【CSP-S 2019模拟】题解

T1:

傻逼题
显然对于一个 i i i,最大的为 ( i i 2 ) {i\choose \frac i 2} (2ii)
用堆维护每一行的最大值
先用对数判大小再在取模的情况下计算答案

#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<20|1;
inline char gc(){
    static char ibuf[RLEN],*ib,*ob;
    (ob==ib)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
    return (ob==ib)?EOF:*ib++;
}
#define gc getchar
inline int read(){
    char ch=gc();
    int res=0,f=1;
    while(!isdigit(ch))f^=ch=='-',ch=gc();
    while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
    return f?res:-res;
}
#define ll long long
#define re register
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define cs const
#define bg begin
#define poly vector<int>
cs int mod=1e9+7;
inline int add(int a,int b){return (a+=b)>=mod?a-mod:a;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
inline int mul(int a,int b){return 1ll*a*b%mod;}
inline void Add(int &a,int b){(a+=b)>=mod?a-=mod:0;}
inline void Dec(int &a,int b){(a-=b)<0?a+=mod:0;}
inline void Mul(int &a,int b){a=1ll*a*b%mod;}
inline int ksm(int a,int b,int res=1){for(;b;b>>=1,Mul(a,a))(b&1)&&(Mul(res,a),1);return res;}
inline int Inv(int x){return ksm(x,mod-2);}
inline void chemx(int &a,int b){a<b?a=b:0;}
inline void chemn(int &a,int b){a>b?a=b:0;}
cs int N=1000005;
pii ans[N];
int tot;
namespace Comb{
	int fac[N],ifac[N];
	inline void init(cs int len=N-5){
		ifac[0]=fac[0]=1;
		for(int i=1;i<=len;i++)fac[i]=mul(fac[i-1],i);
		ifac[len]=Inv(fac[len]);
		for(int i=len-1;i;i--)ifac[i]=mul(ifac[i+1],i+1);
	}
	inline int C(int n,int m){
		return n<m?0:mul(fac[n],mul(ifac[m],ifac[n-m]));
	}
	inline int calc(){
		int res=0;
		for(int i=1;i<=tot;i++)
		Add(res,C(ans[i].fi,ans[i].se));
		return res;
	}
}
#define ldb long double
struct node{
	ldb val;int pos,tim;
	node(ldb _v=0,int _p=0,int _t=0):val(_v),pos(_p),tim(_t){}
	friend inline bool operator <(cs node &a,cs node &b){
		return (a.val==b.val)?(a.pos==b.pos?a.tim<b.tim:a.pos<b.pos):a.val<b.val;
	}
};
priority_queue<node> q;
int vis[N],n,k;
ldb v[N],fac[N];
inline void init(cs int len=N-5){
	for(int i=1;i<=len;i++)v[i]=log2(i);
	for(int i=1;i<=len;i++)fac[i]=fac[i-1]+v[i];
}
inline ldb C(int n,int m){
	return n<m?0:(fac[n]-fac[m]-fac[n-m]);
}
int main(){
	Comb::init(),init();
	n=read(),k=read();
	for(int i=0;i<=n;i++){
		if(i&1)q.push(node(C(i,i/2),i,2));
		else q.push(node(C(i,i/2),i,1));
		vis[i]=i/2;
	}
	while(k>0){
		node now=q.top();q.pop();
		int t=min(k,now.tim);k-=t;
		while(t--)ans[++tot]=pii(now.pos,vis[now.pos]);
		vis[now.pos]--;
		if(vis[now.pos]>=0)q.push(node(C(now.pos,vis[now.pos]),now.pos,2));
	}
	cout<<Comb::calc();
}

T2:

显然暴力是每次建出 T r i e Trie Trie统计答案

考虑这个不好维护,用莫队做
先把整体的 T r i e Trie Trie建出来
每次把一个串的权值加到 T r i e Trie Trie
由于对串分块复杂度会和串长有关
考虑把所有串拼起来分块

这样暴力删每个字符
复杂度就是对的了,每次判断 T r i e Trie Trie上每个节点是否被加入/删除
用一个链表维护每个空段

但是链表只能直接删除和回退
所以要写回滚莫队

复杂度 O ( n n ) O(n\sqrt n) O(nn )

#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<20|1;
inline char gc(){
    static char ibuf[RLEN],*ib,*ob;
    (ob==ib)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
    return (ob==ib)?EOF:*ib++;
}
#define gc getchar
inline int read(){
    char ch=gc();
    int res=0,f=1;
    while(!isdigit(ch))f^=ch=='-',ch=gc();
    while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
    return f?res:-res;
}
#define ll long long
#define re register
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define cs const
#define poly vector<int>
inline void chemx(int &a,int b){a<b?a=b:0;}
cs int N=300005;
int A,B,C,n,m,a[N],num;
int len[N],pos[N],vis[N];
int v[N],g[N],bel[N],L,blo,cnt,fir[N],bg[N],ed[N];
char s[N]; 
ll ans,anc[N],V;
inline ll S(int x){
	return 1ll*x*(x+1)/2;
}
inline ll gcd(ll a,ll b){
	return b?gcd(b,a%b):a;
}
struct opt{
	int l,r,id;
	friend inline bool operator <(cs opt &a,cs opt &b){
		return bel[a.l]==bel[b.l]?a.r>b.r:a.l<b.l;
	}
}p[N];
int pre[N],suf[N],top;
struct node{
	int l,p,r;
	node(int _l=0,int _p=0,int _r=0):l(_l),p(_p),r(_r){}
}stk[N];
inline void getback(){
	while(top){
		int l=stk[top].l,p=stk[top].p,r=stk[top].r;
		ans-=S(r-l-1),ans+=S(p-l-1),ans+=S(r-p-1);
		pre[r]=p,suf[l]=p,top--;
	}
}
inline void delet(int p){
	int l=pre[p],r=suf[p];
	ans-=S(p-l-1)+S(r-p-1),ans+=S(r-l-1);
	stk[++top]=node(l,p,r);
	pre[r]=l,suf[l]=r;
}
inline void build(){
	for(int i=1,last=0;i<=L+1;i++){
		if(vis[i])suf[last]=i,pre[i]=last,ans+=S(i-last-1),last=i;
	}
}
int dep[N],val[N],nxt[N][26],tot;
inline void insert(int id,int coef){
	int p=0;coef*=v[id];
	for(int i=bg[id];i<=ed[id];i++){
		int c=a[i];
		if(!nxt[p][c])nxt[p][c]=++tot,dep[tot]=dep[p]+1;
		p=nxt[p][c];
		int pre=(val[p]>0&&1ll*B*val[p]+1ll*A*dep[p]>=C);
		val[p]+=coef;
		int nxt=(val[p]>0&&1ll*B*val[p]+1ll*A*dep[p]>=C);
		if(!pre&&nxt){vis[g[dep[p]]]++;}
		if(pre&&!nxt){vis[g[dep[p]]]--;if(!vis[g[dep[p]]])delet(g[dep[p]]);}
	}
}
signed main(){
	n=read(),A=read(),B=read(),C=read();
	for(int i=1;i<=n;i++)v[i]=read();
	for(int i=1;i<=n;i++){
		scanf("%s",s+1);
		len[i]=strlen(s+1);
		bg[i]=num+1;
		for(int j=1;j<=len[i];j++)
		a[++num]=s[j]-'a';
		ed[i]=num;
		chemx(L,len[i]);
	}
	for(int i=1;i<=L;i++)g[i]=read();
	m=read();vis[L+1]=1;
	for(int i=1;i<=m;i++)p[i].l=read(),p[i].r=read(),p[i].id=i;
	blo=sqrt(num);
	bel[1]=1;V=S(L);
	for(int i=1,j=2;j<=n;j++){
		bel[j]=bel[j-1];
		if(ed[j]-bg[i]+1>blo)
		bel[j]++,i=j;
	}
	cnt=bel[n];
	sort(p+1,p+m+1);
	for(int i=1;i<=n;i++)
		if(!fir[bel[i]])fir[bel[i]]=i;
	for(int i=1,j,pos=1;i<=cnt;i++){
		ans=0;
		for(j=fir[i];j<=n;j++)insert(j,1);
		build();
		for(j=n;pos<=m&&bel[p[pos].l]==i;pos++){
			while(j>p[pos].r)insert(j,-1),j--;
			top=0;
			for(int k=fir[i];k<p[pos].l;k++)insert(k,-1);
			anc[p[pos].id]=V-ans;
			for(int k=fir[i];k<p[pos].l;k++)insert(k,1);
			getback();
		}
		while(j>=fir[i])insert(j,-1),j--;
	}
	for(int i=1;i<=m;i++){
		ll gg=gcd(V,anc[i]);
		cout<<anc[i]/gg<<"/"<<V/gg<<'\n';
	}
}

T3:

据说出题人用屁眼造数据
造一个半径为小数点后不知道多少位的圆,平方一下就没了的那种

于是咕咕咕

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值