2018"百度之星"程序设计大赛 - 资格赛 A/B/E/F
调查问卷
度度熊为了完成毕业论文,需要收集一些数据来支撑他的论据,于是设计了一份包含 mm 个问题的调查问卷,每个问题只有 'A' 和 'B' 两种选项。
将问卷散发出去之后,度度熊收到了 nn 份互不相同的问卷,在整理结果的时候,他发现可以只保留其中的一部分问题,使得这 nn 份问卷仍然是互不相同的。这里认为两张问卷是不同的,当且仅当存在至少一个被保留的问题在这两份问卷中的回答不同。
现在度度熊想知道,存在多少个问题集合,使得这 nn 份问卷在只保留这个集合的问题之后至少有 kk 对问卷是不同的。
第一行包含一个整数 TT,表示有 TT 组测试数据。
接下来依次描述 TT 组测试数据。对于每组测试数据:
第一行包含三个整数 nn,mm 和 kk,含义同题目描述。
接下来 nn 行,每行包含一个长度为 mm 的只包含 'A' 和 'B' 的字符串,表示这份问卷对每个问题的回答。
保证 1 \leq T \leq 1001≤T≤100,1 \leq n \leq 10^31≤n≤103,1 \leq m \leq 101≤m≤10,1 \leq k \leq 10^61≤k≤106,给定的 nn 份问卷互不相同。
对于每组测试数据,输出一行信息 "Case #x: y"(不含引号),其中 x 表示这是第 xx 组测试数据,y 表示满足条件的问题集合的个数,行末不要有多余空格。
- 2
- 2 2 1
- AA
- BB
- 2 2 2
- AA
- BB
- Case #1: 3
- Case #2: 0
- 注意到m很小,可以暴力枚举所有的子集然后判断不同的对数是否大于等于k。注意可能有多个人的问卷是一样的。
- #include<bits/stdc++.h>
- using namespace std;
- #define LL long long
- #define pb push_back
- #define inf 0x3f3f3f3f
- int vis[];
- char e[][];
- int main(){
- int t,n,q,m,i,j,cas=,k;
- scanf("%d",&t);
- while(t--){
- scanf("%d%d%d",&n,&m,&k);
- for(i=;i<n;++i) scanf("%s",e[i]);
- int ans=,all=((<<m)-);
- for(int i=;i<=all;++i){
- int x=,y=;
- memset(vis,,sizeof(vis));
- for(int j=;j<n;++j){
- x=;
- for(int k=;k<m;++k){
- if(i&(<<k)){
- x<<=;
- if(e[j][k]=='B') x|=;
- }
- }
- vis[x]++;
- }
- LL ss=,tmp=;
- for(int j=;ss<n;++j){
- if(!vis[j]) continue;
- tmp+=1LL*vis[j]*(n-ss-vis[j]);
- ss+=vis[j];
- }
- if(tmp>=k)ans++;
- }
- printf("Case #%d: %d\n",++cas,ans);
- }
- return ;
- }
子串查询
度度熊的字符串课堂开始了!要以像度度熊一样的天才为目标,努力奋斗哦!
为了检验你是否具备不听课的资质,度度熊准备了一个只包含大写英文字母的字符串 A[1,n] = a_1 a_2 \cdots a_nA[1,n]=a1a2⋯an,接下来他会向你提出 qq 个问题 (l,r)(l,r),你需要回答字符串 A[l,r] = a_l a_{l+1} \cdots a_rA[l,r]=alal+1⋯ar 内有多少个非空子串是 A[l,r]A[l,r] 的所有非空子串中字典序最小的。这里的非空子串是字符串中由至少一个位置连续的字符组成的子序列,两个子串是不同的当且仅当这两个子串内容不完全相同或者出现在不同的位置。
记 |S|∣S∣ 为字符串 SS 的长度,对于两个字符串 SS 和 TT ,定义 SS 的字典序比 TT 小,当且仅当存在非负整数 k(\leq \min(|S|,|T|))k(≤min(∣S∣,∣T∣)) 使得 SS 的前 kk 个字符与 TT 的前 kk 个字符对应相同,并且要么满足 |S| = k∣S∣=k 且 |T| > k∣T∣>k,要么满足 k < \min(|S|,|T|)k<min(∣S∣,∣T∣) 且 SS 的第 k+1k+1 个字符比 TT 的第 k+1k+1 个字符小。例如 "AA" 的字典序比 "AAA" 小,"AB" 的字典序比 "BA" 小。
第一行包含一个整数 TT,表示有 TT 组测试数据。
接下来依次描述 TT 组测试数据。对于每组测试数据:
第一行包含两个整数 nn 和 qq,表示字符串的长度以及询问的次数。
第二行包含一个长为 nn 的只包含大写英文字母的字符串 A[1,n]A[1,n]。
接下来 qq 行,每行包含两个整数 l_i,r_ili,ri,表示第 ii 次询问的参数。
保证 1 \leq T \leq 101≤T≤10,1 \leq n,q \leq 10^51≤n,q≤105,1 \leq l_i \leq r_i \leq n1≤li≤ri≤n。
对于每组测试数据,先输出一行信息 "Case #x:"(不含引号),其中 x 表示这是第 xx 组测试数据,接下来 qq 行,每行包含一个整数,表示字符串 A[l,r]A[l,r] 中字典序最小的子串个数,行末不要有多余空格。
- 1
- 2 3
- AB
- 1 1
- 1 2
- 2 2
- Case #1:
- 1
- 1
1- 字典序最小的子串,显然长度是1,做个前缀和统计一下不同字母出现的次数就好了。然后找区间内最小的且出现次数不为零的字母就是答案。
- #include<bits/stdc++.h>
- using namespace std;
- #define LL long long
- #define pb push_back
- #define inf 0x3f3f3f3f
- char s[];
- LL f[][];
- int main(){
- int t,n,q,m,i,j,k,cas=,l,r;
- scanf("%d",&t);
- while(t--){
- scanf("%d%d%s",&n,&q,s+);
- for(i=;i<=n;++i){
- for(j=;j<;++j) f[i][j]=f[i-][j];
- f[i][s[i]-'A']++;
- }
- printf("Case #%d:\n",++cas);
- while(q--){
- scanf("%d%d",&l,&r);
- LL ans=;
- for(i=;i<;++i){
- if(f[r][i]-f[l-][i]){
- ans=f[r][i]-f[l-][i];
- break;
- }
- }
- printf("%I64d\n",ans);
- }
- }
- return ;
- }
序列计数
度度熊了解到,11,22,…,nn 的排列一共有 n! = n \times (n-1) \times \cdots \times 1n!=n×(n−1)×⋯×1 个。现在度度熊从所有排列中等概率随机选出一个排列 p_1p1,p_2p2,…,p_npn,你需要对 kk=11,22,33,…,nn 分别求出长度为 kk的上升子序列个数,也就是计算满足 1 \leq a_11≤a1 < a_2a2 < … < a_kak \leq n≤n 且 p_{a_1}pa1 <p_{a_2}pa2< … < p_{a_k}pak 的 kk 元组 (a_1a1,a_2a2,…,a_kak) 的个数。
由于结果可能很大,同时也是为了 ruin the legend, 你只需要输出结果对 1000000007(=10^9+7)1000000007(=109+7) 取模后的值。
第一行包含一个整数 TT,表示有 TT 组测试数据。
接下来依次描述 TT 组测试数据。对于每组测试数据:
第一行包含一个整数 nn,表示排列的长度。
第二行包含 nn 个整数 p_1p1,p_2p2, …, p_npn,表示排列的 nn 个数。
保证 1 \leq T \leq 1001≤T≤100,1 \leq n \leq 10^41≤n≤104,TT 组测试数据的 nn 之和 \leq 10^5≤105,p_1p1,p_2p2,…,p_npn 是 11,22,…,nn 的一个排列。
除了样例,你可以认为给定的排列是从所有 11,22,…,nn 的排列中等概率随机选出的。
对于每组测试数据,输出一行信息 "Case #x: c_1c1 c_2c2 ... c_ncn"(不含引号),其中 x 表示这是第 xx 组测试数据,c_ici 表示长度为 ii 的上升子序列个数对 1000000007(=10^9+7)1000000007(=109+7) 取模后的值,相邻的两个数中间用一个空格隔开,行末不要有多余空格。
- 2
- 4
- 1 2 3 4
- 4
- 1 3 2 4
不难想到一个O(N*N*log(N))的做法,但是这个数据一直担心会gg,写了之后也确实T了。后来经过大佬指点发现,由于数据是随机的,所以递推到某一个长度之后可能没有任何一种方案,那他之后更大的长度的方案个数也是0,就可以直接退出循环了。加一句话就过了。
f(i,j)表示以第i个数结尾的长度为j的上升序列的方案个数,转移的时候用BIT维护下,要保证当前BIT内的数值都是当前位之前的位置贡献的。
- #include<bits/stdc++.h>
- using namespace std;
- #define LL long long
- #define pb push_back
- #define inf 0x3f3f3f3f
- LL mod=1e9+;
- int a[],N,M;
- LL C[],ans[],f[][];
- inline int lowbit(int x){return x&-x;};
- inline void add(int x,LL d){
- while(x<=N){
- C[x]+=d;
- C[x]%=mod;
- x+=lowbit(x);
- }
- }
- inline LL sum(int x){
- LL r=;
- while(x){
- r+=C[x];
- r%=mod;
- x-=lowbit(x);
- }
- return r;
- }
- inline void scan_d(int &ret)
- {
- char c;
- ret = ;
- while ((c = getchar()) < '' || c > '');
- while (c >= '' && c <= '')
- {
- ret = ret * + (c - ''), c = getchar();
- }
- }
- int main(){
- int t,n,m,i,j,k,cas=;
- char ch;
- scanf("%d",&t);
- while(t--){
- scanf("%d",&n);
- N=n;
- for(i=;i<=n;++i) scan_d(a[i])/*scanf("%d",a+i)*/,f[][i]=;
- ans[]=n;
- int cur=;
- for(int len=;len<=n;++len){
- ans[len]=;
- if(ans[len-]==) continue;
- for(i=;i<=n;++i){
- LL tmp=sum(a[i]-);
- ans[len]+=tmp;
- add(a[i],f[cur^][i]);
- f[cur][i]=tmp;
- }
- //memset(C,0,sizeof(C));
- for(i=;i<=n;++i)C[i]=;
- cur^=;
- }
- printf("Case #%d:",++cas);
- for(i=;i<=n;++i) printf(" %I64d",ans[i]%mod);
- cout<<endl;
- }
- return ;
- }
三原色图
度度熊有一张 nn 个点 mm 条边的无向图,所有点按照 1,2,\cdots,n1,2,⋯,n 标号,每条边有一个正整数权值以及一种色光三原色红、绿、蓝之一的颜色。
现在度度熊想选出恰好 kk 条边,满足只用这 kk 条边之中的红色边和绿色边就能使 nn 个点之间两两连通,或者只用这 kk 条边之中的蓝色边和绿色边就能使 nn 个点之间两两连通,这里两个点连通是指从一个点出发沿着边可以走到另一个点。
对于每个 k=1,2,\cdots,mk=1,2,⋯,m,你都需要帮度度熊计算选出恰好 kk 条满足条件的边的权值之和的最小值。
第一行包含一个正整数 TT,表示有 TT 组测试数据。
接下来依次描述 TT 组测试数据。对于每组测试数据:
第一行包含两个整数 nn 和 mm,表示图的点数和边数。
接下来 mm 行,每行包含三个整数 a,b,wa,b,w 和一个字符 cc,表示有一条连接点 aa 与点 bb 的权值为 ww、颜色为 cc 的无向边。
保证 1 \leq T \leq 1001≤T≤100,1 \leq n,m \leq 1001≤n,m≤100,1 \leq a,b \leq n1≤a,b≤n,1 \leq w \leq 10001≤w≤1000,c \in {R,G,B}c∈{R,G,B},这里 R,G,BR,G,B 分别表示红色、绿色和蓝色。
对于每组测试数据,先输出一行信息 "Case #x:"(不含引号),其中 x 表示这是第 xx 组测试数据,接下来 mm 行,每行包含一个整数,第 ii 行的整数表示选出恰好 ii 条满足条件的边的权值之和的最小值,如果不存在合法方案,输出 -1−1,行末不要有多余空格。
- 1
- 5 8
- 1 5 1 R
- 2 1 2 R
- 5 4 5 R
- 4 5 3 G
- 1 3 3 G
- 4 3 5 G
- 5 4 1 B
- 1 2 2 B
- Case #1:
- -1
- -1
- -1
- 9
- 10
- 12
- 17
- 22
- 跑两次kruscal就好了,一次只用条件一的边,一次用条件二的边。每次跑完之后在依次加入剩下的边更新ans,如果无法联通答案就都是-1了。
- #include<bits/stdc++.h>
- using namespace std;
- #define LL long long
- #define pb push_back
- #define inf 0x3f3f3f3f
- int f[];
- int getf(int u){return f[u]==u?u:f[u]=getf(f[u]);}
- struct Edge{
- int u,v,w,col,sel;
- bool operator<(const Edge& C)const{
- return w<C.w;
- }
- }e[];
- int ans[],N,M;
- void mst(int no){
- int cnt=,cnw=;
- for(int i=;i<=N;++i)f[i]=i;
- for(int i=;i<=M;++i)e[i].sel=;
- for(int i=;cnt<N-&&i<=M;++i){
- if(e[i].col==no) continue;
- int fu=getf(e[i].u),fv=getf(e[i].v);
- if(fu!=fv){
- e[i].sel=;
- cnt++;
- cnw+=e[i].w;
- f[fv]=fu;
- }
- }
- if(cnt!=N-) return;
- if(ans[cnt]==-) ans[cnt]=cnw;
- else ans[cnt]=min(ans[cnt],cnw);
- for(int i=;i<=M;++i){
- if(e[i].sel) continue;
- cnt++;
- cnw+=e[i].w;
- if(ans[cnt]==-) ans[cnt]=cnw;
- else ans[cnt]=min(ans[cnt],cnw);
- }
- }
- int main(){
- int t,n,m,i,j,k,cas=;
- char ch;
- scanf("%d",&t);
- while(t--){
- scanf("%d%d",&n,&m);
- N=n,M=m;
- for(i=;i<=m;++i){
- scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
- //getchar();scanf("%c",&ch);
- cin>>ch;
- if(ch=='R') e[i].col=;
- else if(ch=='G') e[i].col=;
- else if(ch=='B') e[i].col=;
- }
- sort(e+,e++m);
- memset(ans,-,sizeof(ans));
- mst();
- mst();
- printf("Case #%d:\n",++cas);
- for(i=;i<=m;++i) printf("%d\n",ans[i]);
- }
- return ;
- }
2018"百度之星"程序设计大赛 - 资格赛 A/B/E/F的更多相关文章
- 2018"百度之星"程序设计大赛 - 资格赛 - 题集
1001 $ 1 \leq m \leq 10 $ 像是状压的复杂度. 于是我们(用二进制)枚举留下的问题集合 然后把这个集合和问卷们的答案集合 $ & $ 一下 就可以只留下被选中的问题的答 ...
- 2018"百度之星"程序设计大赛 - 资格赛hdu6349三原色(最小生成树)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6349 题目: 三原色图 Time Limit: 1500/1000 MS (Java/Others) ...
- 2018"百度之星"程序设计大赛 - 资格赛 1002 子串查询
题面又是万能的毒毒熊... 实在不想写了,就只写了这题 记26个前缀和查询枚举最小值直接算 实在是氵的死 而且我忘记输出Case #%d 想了很久 >_< #include<bits ...
- 子串查询(二维前缀数组) 2018"百度之星"程序设计大赛 - 资格赛
子串查询 Time Limit: 3500/3000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)Total Subm ...
- 2018"百度之星"程序设计大赛 - 资格赛
调查问卷 Accepts: 1546 Submissions: 6596 Time Limit: 6500/6000 MS (Java/Others) Memory Limit: 262144 ...
- HDU6383 2018 “百度之星”程序设计大赛 - 初赛(B) 1004-p1m2 (二分)
原题地址 p1m2 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total ...
- HDU6380 2018 “百度之星”程序设计大赛 - 初赛(B) A-degree (无环图=树)
原题地址 degree Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Tot ...
- hdu 6082 度度熊与邪恶大魔王(2017"百度之星"程序设计大赛 - 资格赛 )
度度熊与邪恶大魔王 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total S ...
- 2014年百度之星程序设计大赛 - 资格赛 第二题 Disk Schedule
双调欧几里得旅行商问题是一个经典动态规划问题.<算法导论(第二版)>思考题15-1和北京大学OJ2677都出现了这个题目. 旅行商问题描写叙述:平面上n个点,确定一条连接各点的最短闭合旅程 ...
随机推荐
- ToString()格式和用法大全,C#实现保留两位小数的方法
C,货币,2.5.ToString("C"),¥2.50.D,十进制数,25.ToString("D5"),00025.E,科学型,25000.ToString ...
- keySet,entrySet用法 以及遍历map的用法
Set<K> keySet() //返回值是个只存放key值的Set集合(集合中无序存放的)Set<Map.Entry<K,V>> entrySet() //返回映 ...
- HDU 1251 统计难题(字典树模板题)
http://acm.hdu.edu.cn/showproblem.php?pid=1251 题意:给出一些单词,然后有多次询问,每次输出以该单词为前缀的单词的数量. 思路: 字典树入门题. #inc ...
- HDU 5754 Life Winner Bo(各类博弈大杂合)
http://acm.hdu.edu.cn/showproblem.php?pid=5754 题意: 给一个国际象棋的棋盘,起点为(1,1),终点为(n,m),现在每个棋子只能往右下方走,并且有4种不 ...
- 理解 Redis(1) - Redis 简介
Redis 的含义 全称: REmote DIctionary Server 远程词典服务器 由于支持 string, list, set, ordered set, hash 等多重数据结构, 因此 ...
- 【BZOJ】3144: [Hnoi2013]切糕
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3144 MDZZ,不知道为什么被卡常数了/TAT(特判才过去的....论vector的危害性 ...
- 一步到位之INNODB
原文链接:http://imysql.com/2012/09/21/mysql-faq-setup-innodb-quickly.html 快速认识InnoDB InnoDB是MySQL下使用最广泛的 ...
- js code
//在页面增加一个放置图标的区块 if(!document.getElementById('_span_jiucuo')) document.write("<span id='_spa ...
- Qt532.QString::split()
1.效果 和 JS里面 貌似是一样的 1.1.QString 编码转换(https://www.cnblogs.com/CodeSkill/p/5082447.html) 2.代码: void Mai ...
- Eclipse+maven 构建第一个简单的springmvc项目
先给出项目的目录: 在eclipse下使用maven构建第一个springmvc项目步骤如下: 1.创建maven project(此处默认你已了解maven),此处需要注意以下两点 2.创建完毕后会 ...