zoukankan      html  css  js  c++  java
  • CF76C

    考场上傻逼没做出来这题,于是来写个题解

    首先发现复杂度在 (2^k imes k) 的时候是能过的(

    考虑 dfs 每个字符的删除状态,发现瓶颈在于如何求出删除后相邻两个字符的贡献。

    这个贡献可以先考虑一个 naive 的 (n^2) 预处理,枚举两个点对 ((i,j)) ,发现只有在 ([i+1,j-1]) 字符全部删除的时候才能造成贡献,于是算一下 ([i+1,j-1]) 字符的状态。然而,点对 ((i,j)) 也可以对以 ([i+1,j-1]) 字符为子集的删除状态造成贡献。对于这部分的贡献直接上 FWT 即可。

    然而还有一个限制是 (i) 字符和 (j) 字符不能被删除任意一个,套上一个小容斥即可。具体看代码。

    考虑怎么把 (n^2) 优化。枚举 (i) 的过程中,同时有两个点 (j_1),(j_2) 满足 (ch_{j_1}=ch_{j_2}) 时,显然这个 (j_2) 是没有用处的。

    所以每个字符只需要找一遍即可,也就是说我们可以以 (mathcal{O}(nk)) 的复杂度去预处理。

    时间复杂度为 (mathcal{O}(2^k imes k)),瓶颈在于 FWT。顺便一提 FWT 在 (kle 22) 的时候都是能过的,(k=23) 就不行。自己sb觉得过不去就没写头铁去刚另一题

    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    #define fi first
    #define se second
    #define pii pair<int,int>
    #define poly vector<int>
    typedef long long ll;
    const int N=2e5+5,M=30;
    int chr[N],R[N];
    ll b[M][M],a[M],val[1<<22],vv[M];
    int vis[M],n,k,T,ans,all;
    void dfs(int x,int st,ll sum){
    	if(sum>T) return;
    	if(x==k) return (void)(ans+=(sum+val[st]<=T && st!=all));
    	if(vis[x]) dfs(x+1,st|(1<<x),sum+a[x]);
    	dfs(x+1,st,sum+vv[x]);
    }
    poly pos[M];
    pii p[M];int cnt;
    void FWT(ll *f,int n){
    	for(int p=2;p<=n;p<<=1){
    		int len=p>>1;
    		for(int i=0;i<n;i+=p)
    			for(int st=i;st<i+len;++st)
    				f[st+len]+=f[st];		
    	}
    
    }
    signed main(){
    	//freopen("untitled.in","r",stdin);
    	//freopen("untitled.out","w",stdout);
    	cin>>n>>k>>T;char ch;
    	for(int i=1;i<=n;++i){
    		cin>>ch;
    		chr[i]=ch-'A';
    		vis[chr[i]]=1;
    		all|=(1<<chr[i]);
    		pos[chr[i]].push_back(i);
    	}
    	for(int i=0;i<k;++i)
    		sort(pos[i].begin(),pos[i].end());
    	for(int i=0;i<k;++i)
    		cin>>a[i];
    	for(int i=0;i<k;++i)
    		for(int j=0;j<k;++j)
    			cin>>b[i][j];
    	for(int i=2;i<=n;++i)
    		if(chr[i]==chr[i-1]) vv[chr[i]]+=b[chr[i]][chr[i-1]];
    		else R[i]=i+1;
    	for(int i=1;i<n;++i){
    		if(chr[i]==chr[i+1]) continue;
    		int st=0;
    		cnt=0;
    		for(int j=0;j<k;++j)
    			if(!pos[j].size() || pos[j].back()<=i) continue;
    			else{
    				int Pos=lower_bound(pos[j].begin(),pos[j].end(),i)-pos[j].begin();
    				if(chr[i]==j && pos[j].size()>1) p[++cnt]=make_pair(pos[j][Pos+1],j);
    				else p[++cnt]=make_pair(pos[j][Pos],j);
    				//cout<<i<<" "<<char(j+'A')<<" "<<pos[j][Pos]<<endl;
    			}
    		sort(p+1,p+cnt+1);
    		for(int j=1;j<=cnt;++j){
    			if(i==p[j].fi) continue;
    			int tmp=b[chr[i]][p[j].se];
    		//	cout<<i<<" "<<p[j].fi<<" "<<char(p[j].se+'A')<<" "<<tmp<<" "<<st<<" shabi
    ";
    			val[st]+=tmp;
    			val[st|(1<<chr[i])]-=tmp;
    			val[st|(1<<p[j].se)]-=tmp;
    			val[st|(1<<p[j].se)|(1<<chr[i])]+=tmp;
    			if(p[j].se==chr[i]) break;
    			st|=(1<<p[j].se);
    		} 
    	}
    //	for(int i=0;i<1<<k;++i)
    //		cout<<val[i]<<" ";cout<<endl;
    	FWT(val,(1<<k));
    //	for(int i=0;i<1<<k;++i)
    //		cout<<val[i]<<" ";cout<<endl;
    	dfs(0,0,0);
    	cout<<ans;
    	return 0;
    }
    
  • 相关阅读:
    大话数据结构--学习目录
    C语言中的 i++ 和 ++i 的区别
    木紫洁,加油
    vue在组件中使用v-model
    vue的v-model指令原理分析
    表格强制换行 table-layout:fixed
    vue引入jquery插件
    vue中使用stylus编写css
    Java单链表简单实现* @version 1.0
    Java中的面向对象I
  • 原文地址:https://www.cnblogs.com/limit-ak-ioi/p/14030160.html
Copyright © 2011-2022 走看看