2021ccpc女生赛

C (状压DP)

题意:给定一张图,每个节点隶属于一个公司,会有节点属于相同的公司,节点都有一个权值,问从节点1出发,到达第iii个点时能得到的最大价值是多少。

每个公司的红包只能领取一次,假设节点3和5都属于公司2,则若在节点3处领取了红包,则在5处就不能领取了。

数据保证无重边和环。其中点数2≤n≤362\leq n \leq 362≤n≤36。

考虑状态压缩dp,

f[i][j]表示当前在点i,且当前各个公司的状态为j,(j可看成01序列,这一位为1表示已经取过,为0表示未取过),能得到的最大价值f[i][j]表示当前在点i,且当前各个公司的状态为j,(j可看成01序列,这一位为1表示已经取过,为0表示未取过),能得到的最大价值f[i][j]表示当前在点i,且当前各个公司的状态为j,(j可看成01序列,这一位为1表示已经取过,为0表示未取过),能得到的最大价值。

则状态转移为:

if(j&(1<<c[v])) f[v][j]=max(f[v][j],f[u][j-(1<<c[v])]); //取v
else f[v][j]=max(f[v][j],f[u][j]); //不取v

但是注意点的数量为36,因此这样做空间和时间都会超,因此考虑优化。

可以发现,若某个公司只有一家分店,那么我们可以直接取走,因为不会对后续的结果有影响。记为第一类公司。

只有有两家以上分店的公司才会对答案有影响。记为第二类公司。

因为总点数为36,因此第二类公司数量最多为n/2=18n/2=18n/2=18个,那么我们就可以进行转移了:

  1. 若当前终点为第一类公司,则直接取就行。
  2. 若当前终点为第二类公司,需要判断当前状态来进行转移。

为什么这样是对的呢,因为dp是无后效性的,本题也是如此,我们算出了当前节点的最优解,即可推出下一个节点的最优解,因此可以保证结果一定正确。

同时本题的图是一个天然的拓扑图,因此不用在拓扑序上dp,循环枚举起点即可。

code:

#include<bits/stdc++.h>using namespace std;
#define endl '\n'
#define ios std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define int long long
#define x first
#define y second
typedef pair<int,int> pii;//head
const int N=110;
vector<int> e[N];
int c[N],w[N];
int dp[50][1<<19];
vector<int> vv;
int ans[N];
void work()
{int n,m;cin>>n>>m;map<int, int> mp;for(int i=1;i<=n;i++){cin>>c[i];mp[c[i]]++;}for(int i=1;i<=n;i++) cin>>w[i];for(int i=1;i<=m;i++){int a,b;cin>>a>>b;e[a].push_back(b);}e[0].push_back(1);//这里也要连条边,不然点1无法转移for(auto [x,y]:mp){if(y>1) vv.push_back(x);//把所有第二类公司放入}int cnt=vv.size();for(int i=0;i<=n-1;i++){for(int k=0;k<(int)e[i].size();k++){//遍历所有邻点int v=e[i][k];int id=0;bool f=0;for(int j=0;j<cnt;j++){if(c[v]==vv[j]) {id=j; f=1;break;}}if(f){//当前终点为第二类公司for(int j=0;j<(1<<cnt);j++){if(j&(1<<id)) dp[v][j]=max(dp[v][j],dp[i][j-(1<<id)]+w[c[v]]);//若状态j是要取这家的红包,则只能由未取这家的状态转移过来else dp[v][j]=max(dp[v][j],dp[i][j]);ans[v]=max(ans[v],dp[v][j]);}}else {//当前终点为第二类公司for(int j=0;j<(1<<cnt);j++){dp[v][j]=max(dp[v][j],dp[i][j]+w[c[v]]);ans[v]=max(ans[v],dp[v][j]);}}    }}for(int i=1;i<=n;i++) cout<<ans[i]<<endl;
}
signed main()
{ios;int t;t=1;while(t--) work();return 0;
}

F (hash, 最小循环节)

题意:给定一个由字符组成的矩阵,询问q次,每次询问给出x1,x2,y1,y2x1,x2,y1,y2x1,x2,y1,y2,问这个矩阵最小是由哪个矩阵扩展来的,输出该矩阵的大小,即长∗宽长*宽长∗宽的值。

可以看出,行和列的答案是相互独立的,也就是其可以分开计算,那么对于行或列,我们要求的是什么呢?最短的循环的字符串,那和什么很像?对!最小循环节!我们可以用kmpkmpkmp来求出这个最小循环节,那么问题又来了,对于x1,y1,x2,y2x1,y1,x2,y2x1,y1,x2,y2这个矩阵,对于列来说,我们求的其实是个二维的东西,列的每个元素其实是当前行的从y1到y2y1到y2y1到y2的这一段字符串。那么怎么把这一段的内容转化为一个值呢?

对于列来说,我们可以对每一行进行hash,利用hash值来表示这一段的内容是什么,也就把二维转化为了一维问题。

对于行来说操作也类似,对每一列hash即可。

code:

#include<bits/stdc++.h>using namespace std;
#define endl '\n'
#define ios std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define int long long
#define x first
#define y second
typedef pair<int,int> pii;
typedef unsigned long long ull;
//head
const int N=2e3+10,P=1331,mod=1e9+7;ull p[N];
ull r[N][N],c[N][N];
char g[N][N];
ull s[N];
int ne[N];
int n,q;
void init()
{p[0]=1;for(int i=1;i<=n;i++){p[i]=p[i-1]*P;}for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){r[i][j]=r[i][j-1]*P+g[i][j];c[j][i]=c[j][i-1]*P+g[i][j];}}
}
int get(int len)
{for(int i=2,j=0;i<=len;i++){while(j&&s[i]!=s[j+1]) j=ne[j];if(s[i]==s[j+1]) j++;ne[i]=j;}return len-ne[len];//返回最小循环节的长度
}
void work()
{cin>>n>>q;for(int i=1;i<=n;i++){cin>>g[i]+1;}init();while(q--){int x1,y1,x2,y2;cin>>x1>>y1>>x2>>y2;//分别处理行和列,找到最小循环节,相乘就是答案for(int i=x1;i<=x2;i++){//处理列s[i-x1+1]=r[i][y2]-r[i][y1-1]*p[y2-y1+1];}int len=x2-x1+1;int L=get(len);for(int i=y1;i<=y2;i++){//处理行s[i-y1+1]=c[i][x2]-c[i][x1-1]*p[x2-x1+1];}len=y2-y1+1;int R=get(len);cout<<L*R<<endl;}
}
signed main()
{ios;int t;t=1;while(t--) work();return 0;
}

B (倍增)

题意:给定一个长度为nnn,且只由字母表前mmm个字母组成的字符串SSS,(不一定全部包含前m个字母),给出q次询问,每次询问给出l,rl,rl,r,让你构造出一个长度为kkk的字符串TTT(也只能由前m个字母组成),使得TTT不是Sl...SrS_l...S_rSl​...Sr​的子序列,求出最小的k的值(不用真的构造出TTT)。

1≤n≤2∗1051\leq n \leq 2*10^51≤n≤2∗105 , 1≤q≤2∗1051\leq q \leq 2*10^51≤q≤2∗105

注意到n和q都比较大,因此考虑怎么把结果预处理出来。怎么计算出结果呢?考虑怎么构造T使得k最小,对于T的某个字符来说,可以有m种选择,假设当前选择了SiS_iSi​ ,那么下一步要选的位置为这m种字符中离iii最远的位置,若某种字符不存在,直接跳出选择。

我们可以把这种不断选择看成跳到某个位置,另f[i][j]表示当前在位置i,跳(选择)2j次可以到达的最远位置f[i][j]表示当前在位置i,跳(选择)2^j次可以到达的最远位置f[i][j]表示当前在位置i,跳(选择)2j次可以到达的最远位置。

我们可以通过倍增来预处理出fff数组,同时注意fff数组的初始化。

code:

#include<bits/stdc++.h>using namespace std;
#define endl '\n'
#define ios std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define int long long
#define x first
#define y second
typedef pair<int,int> pii;//head
const int N=2e5+10;
int f[N][20];
int pos[50];
int m,n;
string s;
void init()
{vector<int> pos(26,n+1);//pos表示每个字符出现的位置,要实时更新//f[i][j]表示当前在第i位置,下一步有m种选择可以跳,跳2^j次后到达的最大位置for(int i=0;i<20;i++) f[n+1][i]=n+1;for(int i=n;i>=0;i--){for(int j=0;j<m;j++){f[i][0]=max(f[i][0],pos[j]);//取最远的那个字符}if(i) pos[s[i]-'a']=i;//更新pos,因为要算下一步跳的最远位置}for(int j=1;j<20;j++){for(int i=0;i<=n;i++){f[i][j]=f[f[i][j-1]][j-1];}}
}
void work()
{cin>>m>>n;cin>>s; s=" "+s;init();int q;cin>>q;while(q--){int l,r;cin>>l>>r;int ans=0,p=l-1;for(int j=19;j>=0;j--){if(f[p][j]<=r){p=f[p][j];ans+=(1<<j);}}cout<<ans+1<<endl;}
}
signed main()
{ios;int t;t=1;while(t--) work();return 0;
}

2021ccpc女生赛 BCF题解相关推荐

  1. 2021CCPC女生赛

    2021CCPC女生赛 距离女生赛过去已经一个月了,竟然没有补题和整理过.每天要看论文做实验还要准备一个又一个的考试,时间总是不够用的,状态还是依然的差. 现场大概5题银首到铜尾了. 金牌的话要做出更 ...

  2. 第二届CCPC女生赛 粗略题解(要做重现的不要看哦)

    因为再不全力投入华为软件精英挑战赛就来不及了! 而且直播时讲过题了,所以只能粗略写一个题解,希望大家包涵>.< 基本可以参考代码,可以画图模拟加思考脑补其原理与过程23333~~ 会后续有 ...

  3. 2021CCPC网络赛部分题解

    先不说杭电服务器的事,自己打的真的垃圾. 学了好久,还是没有好的成绩就是很难受. 目录 1001: Cut The Wire[难度: 简单 / 知识点: 规律] 1006: Power Sum[难度: ...

  4. 2021CCPC女生赛总结

    赛前 可以说赛前一周的时候全队狂练线段树的应用,有点可惜比赛的时候没有遇到线段树的题目.可爱的队长听信民间传闻,听说打屁股会变聪明,疯狂来揍队友,哭哭酱了~ 比赛的前一天打了热身赛,热身赛的前两题写的 ...

  5. 2021CCPC新疆省赛题解BDEFGHIJK

    2021CCPC新疆省赛题解BDEFGHIJK K. chino with c language 题意 memcpy()memcpy()memcpy()不会检查源地址范围与目标地址范围是否重叠,它只从 ...

  6. 2021CCPC江西省赛题解ABGHIJKL

    2021CCPC江西省赛题解ABGHIJKL K. Many Littles Make a Mickle 题意 有 t ( 1 ≤ t ≤ 100 ) t\ \ (1\leq t\leq 100) t ...

  7. 2019CCPC江苏南京女生赛 | 总结

    今年的女生专场在江苏南京晓庄学院举办 (夸一波 主办方周老师好可爱~~ 桌牌设计的很好看 志愿者小姐姐也很热心~ 第一次见到了wls.谈姐姐等巨巨 很难得在开头放队友友链 因为这一篇说的实在是太废话了 ...

  8. 武汉工程大学第一届程序设计女生赛(牛客contest 4746)解题报告 Apare_xzc

    武汉工程大学第一届程序设计女生赛解题报告 xzc 2020.3.8 比赛链接:武汉工程大学第一届程序设计女生赛 A. Multiplication (101/861) 分析: 问x平方几次后就会> ...

  9. 科林明伦杯哈理工第十届同步赛部分题解

    科林明伦杯哈理工第十届同步赛部分题解 B题 搭积木问题 F题 三角形 B题 搭积木问题 链接:https://ac.nowcoder.com/acm/contest/5758/B 来源:牛客网 题目描 ...

最新文章

  1. 5 门前途美好的编程语言
  2. TImm 笔记: 训练模型
  3. 计算机组成原理B1,计算机组成原理-本科生期末试卷B1.doc
  4. 诺奖技术和高通量筛选双双找到新冠病毒的脉门
  5. 高性能HTTP加速器Varnish(安装配置篇)
  6. oracle脚本加并发,定时执行ORACLE脚本,并发邮件到指定邮箱
  7. 计算机怎么清理CAD,注册表cad,如何清理cad软件在注册表残留
  8. leetcode【链表—中等】707.设计链表
  9. 计算机病毒存于什么,计算机病毒防治体系存在的问题有什么
  10. php面向对象常见的专业术语
  11. 基于u-net,cv2以及cnn的中文车牌定位,矫正和端到端识别软件
  12. APM的3DR无线数传的安装和调试
  13. 爬虫之上传文件,request如何上传文件
  14. JAVA基础--java简单知识04(类与对象,封装,继承,多态)
  15. 插画师所需的基础软件
  16. 浅析产品新手引导设计
  17. 综合布线系统桥架型式及品种选择
  18. c语言摄氏度变为温度用int,C语言打印华氏-摄氏温度对照表的方法
  19. N78接班N73的九大显著改进
  20. “三顾字节”,九次面试,只要算法搞得好,大厂offer跑不了

热门文章

  1. 星座判断选择(GO语言)
  2. 关于CSDN如何修改用户名与解绑手机号的问题分析
  3. Git提交无法检测到邮箱问题!
  4. HRNet-OCR网络结构详解
  5. Android 开发从入门到实战
  6. Cesium|xt3d扩散围墙
  7. 代表作须1/3国内论文,版面费超2万须严审,黑名单论文不予报销……破除“唯论文”又有一省跟进!...
  8. Afaria 7服务器升级过程
  9. 19年广东一战插本上岸啦!!!(来自一个自学上岸插本生的攻略)
  10. 牛客小白月赛7 B自杀游戏(sg博弈)