[Codeforces Round #542 [Alex Lopashev Thanks-Round] (Div. 1)]

[Codeforces Round #542 (Div. 1)] B,C,D,E


链接

  • B

第一个是 -1 ,然后随便构造

#include<bits/stdc++.h>
using namespace std;
const int N=2010;
int sub,n;
int a[N];
int main()
{
	scanf("%d",&sub);
	a[1]=-1;
	for(int l=1;l<N;l++){
		if(l*1000000>=sub+(l+1)){
			n=l+1;break;
		}
	}
	sub+=n;
	printf("%d\n",n);
	for(int i=1;i<=n;i++){
		if(i==1)a[i]=-1;
		else a[i]=min(sub,1000000);
		if(i>1)sub-=a[i];
	}
	for(int i=n;i>1;i--){
		if(a[i]){
			a[i]-=min(sub,a[i]-1);
			sub-=min(sub,a[i]-1);
		}
		if(!a[i]){
			a[i]++;
			sub++;
		}
	}
	for(int i=1;i<=n;i++)printf("%d ",a[i]);puts("");
}
  • C

后缀自动机然后dp一下,每次把新的子串的dp值加上去

#include<bits/stdc++.h>
using namespace std;
const int N=4010;
int a[N*2];
int n;
const int mod=1e9+7;
struct SAM{
	struct node{
		int len,ch[2],right,par;
	}t[N*3];
	int cnt,root,tail;
	inline int newnode(int _len){
		++cnt;t[cnt].len=_len;return cnt;
	}
	inline void init(){
		root=tail=newnode(0);
	}
	inline int extend(int c){
		int np=newnode(t[tail].len+1),p=tail;
		while(p&&!t[p].ch[c])t[p].ch[c]=np,p=t[p].par;
		if(p==0)t[np].par=root;
		else if(t[t[p].ch[c]].len==t[p].len+1)t[np].par=t[p].ch[c];
		else {
			int nq=newnode(t[p].len+1),q=t[p].ch[c];
			memcpy(t[nq].ch,t[q].ch,sizeof(t[q].ch));t[nq].par=t[q].par;
			t[q].par=t[np].par=nq;
			while(p&&t[p].ch[c]==q)t[p].ch[c]=nq,p=t[p].par;
		}
		t[np].right=1,tail=np;
		return t[t[np].par].len+1;
	}
}sam;
int minlen[N];
int f[N][N];
bool judge(int l,int r){
	if(r-l+1<4)return 1;
	if(r-l+1>4)return 0;
	int tmp=a[l]+a[l+1]*2+a[l+2]*4+a[l+3]*8;
	if(tmp==12||tmp==15||tmp==10||tmp==7)return false;
	return true;
}
int main()
{
	scanf("%d",&n);
	sam.init();
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		minlen[i]=sam.extend(a[i]);
//		cout<<"::"<<minlen[i]<<endl;
	}
	for(int i=1;i<=n;i++){
		f[i][i-1]=1;
		for(int j=i;j<=n;j++){
			for(int k=j-1;k>=max(i-1,j-4);k--)if(judge(k+1,j)){
				f[i][j]+=f[i][k];
				f[i][j]%=mod;
			}
		}
	}
//	cout<<f[1][3]<<"!"<<endl;
	int ans=0;
	for(int i=1;i<=n;i++){
		int R=i-minlen[i]+1;
		for(int j=1;j<=R;j++)ans=(ans+f[j][i])%mod;
		printf("%d\n",ans);
	}
}
  • D

记下pre了之后每次会修改两个区间的值,一个+1,一个-1,我们需要查询一个区间的值。

这个可以分块维护,就可以dp了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=998244353;
inline int add(int a,int b){a+=b;return a>=mod?a-mod:a;}
inline int sub(int a,int b){a-=b;return a<0?a+mod:a;}
inline int mul(int a,int b){return (ll)a*b%mod;}
inline int qpow(int a,int b){int ret=1;for(;b;b>>=1,a=mul(a,a))if(b&1)ret=mul(ret,a);return ret;}
/*math*/
const int N=1e5+5;
const int BLK=400;
int n,qk,K;
int pre[N],lst[N],cnt[N],_tmp[N];
int tag[BLK],l[BLK],r[BLK],sum[BLK][N],ans[BLK];
int bl[N],f[N],dp[N],a[N];

inline void rebuild(int x){
	for(int k=l[x];k<=r[x];k++)sum[x][f[k]]=0;
	for(int k=l[x];k<=r[x];k++)f[k]+=tag[x];
	tag[x]=0;ans[x]=0;
	for(int k=l[x];k<=r[x];k++){
		sum[x][f[k]]=add(sum[x][f[k]],dp[k]);
		ans[x]=add(ans[x],f[k]<=qk?dp[k]:0);
	}
}
inline void upd(int x,int fff,int del=true){
	int b=bl[x];
	if(del){
		sum[b][f[x]]=sub(sum[b][f[x]],dp[x]);
		if(f[x]<=qk)ans[b]=sub(ans[b],dp[x]);
	}
	f[x]+=fff;
	sum[b][f[x]]=add(sum[b][f[x]],dp[x]);
	if(f[x]<=qk)ans[b]=add(ans[b],dp[x]);
}
inline void ADD(int L,int R,int f){
	if(bl[L]==bl[R]){
		rebuild(bl[L]);
		for(int k=L;k<=R;k++){
			upd(k,f);
		}
		return ;
	}
	rebuild(bl[L]);
	for(int k=L;k<=r[bl[L]];k++)upd(k,f);
	for(int k=bl[L]+1;k<=bl[R]-1;k++){
		if(f==1){
			int tk=qk-tag[k];
			ans[k]=sub(ans[k],sum[k][tk]);
			++tag[k];
		}else{
			--tag[k];
			int tk=qk-tag[k];
			ans[k]=add(ans[k],sum[k][tk]);
		}
	}
	rebuild(bl[R]);
	for(int k=l[bl[R]];k<=R;k++)upd(k,f);
}
inline int query(int x){
	int res=_tmp[x]+dp[x];
	for(int k=1;k<=bl[x]-1;k++)res=add(res,ans[k]);
	for(int k=l[bl[x]];k<x;k++)res=add(res,f[k]<=qk?dp[k]:0);
	return res;
}
int main()
{
	scanf("%d%d",&n,&qk);K=sqrt(n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		pre[i]=lst[a[i]];lst[a[i]]=i;
	}
	for(int i=1;i<=n;i++){
		bl[i]=(i-1)/K+1;
		r[bl[i]]=max(r[bl[i]],i);
		if(!l[bl[i]])l[bl[i]]=i;
	}
	dp[1]=1;
	for(int i=1;i<=n;i++){
		if(i!=1&&pre[i]+1!=i){
			ADD(pre[i]+1,i-1,1);
		}
		if(pre[i])ADD(pre[pre[i]]+1,pre[i],-1);
		dp[i+1]=query(i);
		rebuild(bl[i]);
		upd(i,1);
	}
	cout<<dp[n+1]<<endl;
}
  • E

首先查询1,tot,i可以查1为根时i的size。然后我们按照size排序之后每次二分找没找到fa的点,以此确定一个fa。

就能在规定次数内做出来了。

#include<bits/stdc++.h>
using namespace std;
typedef vector<int> vec;
int query(vector<int> A,int sza,vector<int> B,int szb,int T){
	printf("%d\n",sza);
	for(int i=0;i<sza;i++)printf("%d ",A[i]);puts("");
	printf("%d\n",szb);
	for(int i=0;i<szb;i++)printf("%d ",B[i]);puts("");
	printf("%d\n",T);
	fflush(stdout);
	int ans=0;scanf("%d",&ans);
	return ans;
}
const int N=510;
int n;
vec t;vec node;
int del[N];int sz[N];


bool cmp(const int a,const int b){return sz[a]>sz[b];}

struct edge{
	int u,v;
	edge(int u=0,int v=0):u(u),v(v){}
}e[N];int cnt=0;

int qry(int l,int r,int id){
	vector<int>Q;
	Q.resize(0);
	for(int i=l;i<=r;i++)if(!del[node[i]]){
		Q.push_back(node[i]);
	}
	if(Q.size()==0)return 0;
	return query((vector<int>){1,1},1,Q,Q.size(),id);
}

int main()
{
	scanf("%d",&n);
	for(int i=2;i<=n;++i){
		t.push_back(i);
	}
	sz[1]=n;
	node.push_back(1);
	for(int i=2;i<=n;i++){
		sz[i]=query((vector<int>){1,1},1,t,n-1,i);
		node.push_back(i);
//		cout<<i<<","<<sz[i]<<endl;
	}
//	puts("----");
	sort(node.begin(),node.end(),cmp);
	for(int i=n-1;~i;i--){
		int x=node[i];
//		cout<<x<<" "<<sz[x]<<"::"<<endl;
		sz[x]--;
		if(sz[x]==0)continue;
		while(qry(i+1,n-1,x)){
			int l=i+1,r=n-1;
			while(l<r){
				int mid=(l+r)>>1;
				int ret=qry(i+1,mid,x);
				if(ret==0){
					l=mid+1;
				}else{
					r=mid;
				}
			}
			e[++cnt]=edge(x,node[l]);
			sz[x]--;del[node[l]]=1;
		}
	}
	puts("ANSWER");
	for(int i=1;i<=cnt;i++)cout<<e[i].u<<" "<<e[i].v<<endl;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值