zoukankan      html  css  js  c++  java
  • CF1017D Solution

    题目链接

    题解

    (n)的数字范围很小,又加之01串的条件,容易想到状压。01串的个数很少,一共只有(2^{12}=4096)个,而其余都是重复的,并且(w,kle 100),可以想到将每个字符串在不同(k)时的答案预处理。具体方法受Trie树的启发,想到将集合(S)中的01串以二叉树存储,如题目中样例1可建立如下的树:

    递归过程中,记录经过节点的权值和(sum)(设当前层数为(pos),如果01值不同权值为零,否则为(w_{pos})),到达叶子节点时该01串(k)(sum)时的答案,可以加上叶子节点所指向(S)中01串的个数。如样例1中串(00),到达上方叶子节点时(sum=40),因此(k=40)(00)的答案(+=2)

    AC题解

    #include<bits/stdc++.h>
    using namespace std;
    const int N=15,M=5e5+10,S=(1<<12)+10;
    struct node {char str[N]; int v,k,id;} a[M];
    //a:询问——str:原01串,v:状压值,id:原下标 
    char s[M][N]; 
    int w[N],t[4*S][2],num[4*S],qwq[S][N*110],cnt,n;
    //t:类Trie的二叉树,num:叶子节点01串数量,qwq[i][j]:状压值为i,k为j询问的答案,cnt:树中节点数量 
    bool cmp(node a,node b) {return a.v<b.v;}
    bool cmp2(node a,node b) {return a.id<b.id;}
    void add(char *b)//将新01串加入树中
    {
    	int pos=0;
    	for(int i=1;i<=n;i++)
    	{
    		bool ti=b[i]-'0';
    		if(!t[pos][ti]) t[pos][ti]=++cnt;
    		pos=t[pos][ti];
    		if(i==n) num[pos]++;
    	}
    } 
    void cul(node b,int x,int pos,int sum)//计算每个询问中01串的qwq
    //x:树中下标,pos:串中下标,sum:Wu值总和 
    {
    	bool tmp=b.str[pos]-'0';
    	if(pos==n) {qwq[b.v][sum]+=num[x]; return;}
    	if(t[x][tmp]) cul(b,t[x][tmp],pos+1,sum+w[pos]);
    	if(t[x][tmp^1]) cul(b,t[x][tmp^1],pos+1,sum);
    }
    int main()
    {
    	int m,q;
    	scanf("%d%d%d",&n,&m,&q);
    	for(int i=0;i<n;i++) scanf("%d",&w[i]);
    	for(int i=1;i<=m;i++) {scanf("%s",s[i]+1); add(s[i]);}
    	for(int i=1;i<=q;i++) 
    	{
    		scanf("%s%d",a[i].str,&a[i].k); a[i].id=i;
    		for(int j=0;j<n;j++) a[i].v+=(a[i].str[j]-'0')*(1<<j);//二进制转十进制(求状压值)
    	}
    	sort(a+1,a+q+1,cmp); a[0].v=-1;//使v相同询问在一起
    	for(int i=1;i<=q;i++)
    	{
    		if(a[i].v==a[i-1].v) continue;
    		cul(a[i],0,0,0);
    	}
    	for(int i=1;i<=q;i++)
    	{
    		if(a[i].v!=a[i-1].v)//>=j的询问均可以使用j的答案,因此需要累加
    			for(int j=1;j<=100;j++) qwq[a[i].v][j]+=qwq[a[i].v][j-1];
    	} 
    	sort(a+1,a+q+1,cmp2);//按原序排序,以便输出
    	for(int i=1;i<=q;i++) printf("%d
    ",qwq[a[i].v][a[i].k]);
    	return 0;
    }
    
  • 相关阅读:
    定时自动备份数据库
    读<你必须知道的.NET>小结3
    [转载]手把手教你用C#打包应用程序(安装程序)【卸载模块已添加】
    集成测试
    P2P
    20110818炒股日记急拉慢跌的走势
    xp sp3安装IIS
    调用ASP.NET工作流:承载及限制
    20110822炒股日记进入筑底阶段
    用Duplex实现消息广播
  • 原文地址:https://www.cnblogs.com/violetholmes/p/14336466.html
Copyright © 2011-2022 走看看