2018_10_7 模拟赛

99 篇文章 1 订阅
21 篇文章 0 订阅

前言

OTL


hdu 6344 调查问卷

题目

n n n份互不相同的问卷,在整理结果的时候,他发现可以只保留其中的一部分问题,使得其中 k k k份问卷仍然是互不相同的。这里认为两张问卷是不同的,当且仅当存在至少一个被保留的问题在这两份问卷中的回答不同。问有多少个问题的子集满足以上要求


分析

然而(比赛)题目比较玄学,可能理解有问题,但是实际上还是知道的,由于问题数较少,可以用状态压缩,枚举子集,用总共的 C n 2 C_n^2 Cn2减掉重复的(可以用一个数组标记),当 ≥ \geq k那么累计答案


代码

#include <cstdio>
#include <cstring>
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<13,stdin)),p1==p2?EOF:*p1++)
#define rr register
using namespace std;
int s[1000001][26]; char buf[1<<13],*p1,*p2;
inline signed in(){
	rr int ans=0; rr char c=getchar();
	while (c<48||c>57) c=getchar();
	while (c>47&&c<58) ans=(ans<<3)+(ans<<1)+c-48,c=getchar();
	return ans;
}
inline signed print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
signed main(){
	rr int t=in();
	for (rr int o=1;o<=t;++o){
		printf("Case #%d: ",o);
		rr int n=in(),m=in(),k1=in(),ans=0;
		rr int a[n+1];
		for (rr int i=1;i<=n;++i){
			a[i]=0; rr char c=getchar();
			while (c!='A'&&c!='B') c=getchar();
			for (rr int j=1;j<=m;++j) a[i]=(a[i]<<1)+(c=='A'),c=getchar();//状态压缩
		}
		for (rr int i=0;i<(1<<m);++i){
			rr int v[1<<m]; memset(v,0,sizeof(v)); rr int k=0;
			for (rr int j=1;j<=n&&k<k1;++j) k+=j-(++v[i&a[j]]);//重复的考卷用v标记
			if (k>=k1) ans++;
		}
		if (ans) print(ans); else putchar(48);
		putchar(10);
	}
	return 0;
}

hdu 6345 子串查询

题目

问区间最小大写字母的个数


分析

由于大写字母只有26个,所以可以用前缀和,然后AC这道题其实是比较简单的,当然听说有 O ( n ) O(n) O(n)的方法,只能膜拜dalao了


代码

#include <cstdio>
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<13,stdin)),p1==p2?EOF:*p1++)
#define rr register
using namespace std;
int s[100001][26]; char buf[1<<13],*p1,*p2;
inline signed in(){
	rr int ans=0; rr char c=getchar();
	while (c<48||c>57) c=getchar();
	while (c>47&&c<58) ans=(ans<<3)+(ans<<1)+c-48,c=getchar();
	return ans;
}
inline signed print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
signed main(){
	rr int t=in();
	for (rr int o=1;o<=t;++o){
		printf("Case #%d:\n",o);
		rr int n=in(),q=in(); rr char c=getchar();
		while (c<65||c>90) c=getchar();
		for (rr int i=1;i<=n;++i,c=getchar())
		for (rr int j=0;j<26;++j) s[i][j]=s[i-1][j]+(c==j+65);
		while (q--){
			rr int l=in(),r=in();
			if (l>r) putchar(48);//反正加上比较舒服
			else for (rr int j=0;j<26;++j)
			if (s[r][j]-s[l-1][j]){//前缀和差分
				print(s[r][j]-s[l-1][j]);
				break;//直接退出
			}
			putchar(10);
		}
	}
	return 0;
}

hdu 6348 序列计数

题目

k ∈ [ 1 … n ] k\in[1\dots n] k[1n]时,子上升序列长度为 k k k的个数


分析

一道动态规划的题目,设 d p [ i ] [ j ] dp[i][j] dp[i][j]为子序列长度为 i i i,以j结尾的个数,那么状态转移方程是
d p [ i ] [ j ] = ∑ { d p [ i − 1 ] [ k ] , k ∈ [ 1 … j − 1 ] 且 a [ k ] &lt; a [ j ] } , d p [ 1 ] [ i ] = 1 dp[i][j]=\sum\{dp[i-1][k],k\in[1\dots j-1]且a[k]&lt;a[j]\},dp[1][i]=1 dp[i][j]={dp[i1][k],k[1j1]a[k]<a[j]},dp[1][i]=1
问题是这样枚举k必然 O ( n 3 ) O(n^3) O(n3)会超时,所以选择如何一次到位,然后就可以用树状数组维护,那么时间就变成了 O ( n 2 l o g 2 n ) O(n^2log_2n) O(n2log2n),然而目测还是会超时,那么由于是随机数据,会等概率,所以其实实测时间复杂度在 O ( n n l o g 2 n ) O(n\sqrt nlog_2n) O(nn log2n)左右


代码

#include <cstdio>
#include <cstring>
#define rr register
#define mod 1000000007
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<13,stdin)),p1==p2?EOF:*p1++)
using namespace std;
char buf[1<<13],*p1,*p2;
inline signed in(){
	rr int ans=0; rr char c=getchar();
	while (c<48||c>57) c=getchar();
	while (c>47&&c<58) ans=(ans<<3)+(ans<<1)+c-48,c=getchar();
	return ans;
}
inline signed print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
signed main(){
	rr int t=in();
	for (rr int o=1;o<=t;++o){
		printf("Case #%d: ",o);
		rr int n=in(),flag=1; print(n);
		rr int a[n+1],c[n+1],dp[n+1][2];//滚动数组
		for (rr int i=1;i<=n;++i) a[i]=in(),dp[i][1]=1;
		for (rr int j=2,now=0;j<=n;++j,now^=1){
			putchar(32);
			if (!flag){//只要有一个答案为0那么后面都是0
				putchar(48);
				continue;
			}
			for (rr int i=1;i<=n;++i) c[i]=0;//初始化树状数组为0
			for (rr int i=1;i<=n;++i){
				rr int x=a[i]-1; dp[i][now]=0;
				while (x) dp[i][now]=(dp[i][now]+c[x])%mod,x-=-x&x;//更新答案
				x=a[i];
				while (x<=n) c[x]=(c[x]+dp[i][now^1])%mod,x+=-x&x;//那么取上一次更新树状数组
			}
			rr int ans=0;
			for (rr int i=1;i<=n;++i) ans=(ans+dp[i][now])%mod;//计算和
			if (!ans) flag=0,putchar(48); else print(ans);
		}
        putchar(10);
	}
	return 0;
}

后续

经常被ssl_xxy,ssl_lw,ssl_hjq,ssl_lrz,ssl_hzb,ssl_wyc和ssl_zyc吊打,非常不爽

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值