Problem A  旅行者

有$n$种转移装置,每种转移装置本质相同,每种装置可以前进$a_i$单位,但只有$b_i$个。

从初始坐标为$0$出发,途中不能经过$c_1,c2,...,c_m$中的任意一个点。

走到$\sum\limits_{i = 1}^n a_ib_i$位置的方案数$mod 10^9 + 7$的值。

对于$100\%$的数据满足$1 \leq n \leq 6 , 1 \leq m \leq 10^5 ,0<c_i < \sum\limits_{i = 1}^n a_ib_i$

  Solution :

    由于每个装置本质相同,那么我们只需要记录当前使用的转移装置数作为状态即可。

    这样定义状态的总状态数时$\prod_{i = 1}^n b_i \leq 13^6 = 4826809$

    注意,由于有$m$点不能走,还需要开一个$hash$存当前值能不能走,特殊判掉即可。

    转移的时候枚举当前通过那个转移装置走到当前位置,转移时间复杂度为$O(n)$

    请注意,本题的模数为$10^8 + 7$,您是否数错了零?

    所以,本题的总时间复杂度是$O(n\prod\limits_{i=1}^{n} b_i)$

# pragma GCC optimize()
# include<bits/stdc++.h>
# define int long long
# define hash Hash
# define Rint register int
using namespace std;
const int mo=;
int f[][][][][][];
struct rec{int a,b;}a[];
int n,m;
vector<int>hash[];
inline int read() {
int X=,w=; char c=;
while(c<''||c>'') {w|=c=='-';c=getchar();}
while(c>=''&&c<='') X=(X<<)+(X<<)+(c^),c=getchar();
return w?-X:X;
}
void insert(int key) {
int k = key % ,sz = hash[k].size();
for (int i=;i<sz;i++) if (hash[k][i] == key) return;
hash[k].push_back(key);
}
bool find(int key) {
int k=key % ,sz = hash[k].size();
for (int i=;i<sz;i++) if (hash[k][i] == key) return true;
return false;
}
signed main() {
n=read();
for (Rint i=;i<=n;i++) {
a[i].a=read(); a[i].b=read();
}
m=read();
for (Rint i=;i<=m;i++) {
int t=read(); insert(t);
}
f[][][][][][]=;
for (Rint a1=;a1<=a[].b;a1++) for (Rint a2=;a2<=a[].b;a2++)
for (Rint a3=;a3<=a[].b;a3++) for (Rint a4=;a4<=a[].b;a4++)
for (Rint a5=;a5<=a[].b;a5++) for (Rint a6=;a6<=a[].b;a6++) {
int tmp = a1*a[].a+a2*a[].a+a3*a[].a+a4*a[].a+a5*a[].a+a6*a[].a;
if (find(tmp)) {
f[a1][a2][a3][a4][a5][a6]=;
continue;
}
if (a1+<=a[].b) (f[a1+][a2][a3][a4][a5][a6]+=f[a1][a2][a3][a4][a5][a6])%=mo;
if (a2+<=a[].b) (f[a1][a2+][a3][a4][a5][a6]+=f[a1][a2][a3][a4][a5][a6])%=mo;
if (a3+<=a[].b) (f[a1][a2][a3+][a4][a5][a6]+=f[a1][a2][a3][a4][a5][a6])%=mo;
if (a4+<=a[].b) (f[a1][a2][a3][a4+][a5][a6]+=f[a1][a2][a3][a4][a5][a6])%=mo;
if (a5+<=a[].b) (f[a1][a2][a3][a4][a5+][a6]+=f[a1][a2][a3][a4][a5][a6])%=mo;
if (a6+<=a[].b) (f[a1][a2][a3][a4][a5][a6+]+=f[a1][a2][a3][a4][a5][a6])%=mo;
}
printf("%lld\n",f[a[].b][a[].b][a[].b][a[].b][a[].b][a[].b]%mo);
return ;
}

traveller.cpp

Problem B 序列

定义两个数$(x,y)$是好的,当且仅当$x \leq y$且$x \oplus y$二进制表示下含有奇数个$1$。

现在给出$n$个区间$[l_i,r_i]$,对于每一个$i\in[1,n]$,输出前$i$个区间并中好的数对的个数。

即输出满足下列条件的$(x,y)$的对数。

  • $x,y \in\cup_{j=1}^i [l_j,r_j]$
  • $x\leq y$
  • $x \oplus y$二进制表示下含有奇数个$1$。

对于$100\%$的数据满足$1 \leq n \leq 10^5 , 1\leq l_i\leq r_i\leq 2^{32}-1$

  Solution :

​     首先,$x \oplus y$的二进制表示下有奇数个$1$有充要条件:一个数有偶数个$1$,一个数有奇数个$1$ 。

​     设$x,y$按二进制位写开来,同$1$的数的对数为$w$,那么剩余的奇数个$1$和偶数个$1$都会对答案产生$1$的贡献。

​     如果我们要统计数集$S$中好的数对的个数,我们就只要数一数这个数集中有多少个数含有偶数个$1$,有多少数有奇数个一,即可。最后的答案就是他们两个之积。

​     如何求一个区间$[l,r]$内有多少个数含有奇数个$1$或者偶数个$1$呢。

​     我们只要求前缀和即可,问题转化为求$[1,x]$的答案。

​     观察到一对数$0,1 ; 2, 3 ; 4,5 ... $从$0$开始每两个数一组一定是一个数字含有奇数个$1$,另外一个数字含有偶数个$1$.

​     所以,若$x$是奇数,$[1,x]$的答案直接是$x/2$了; 否则还需要特殊判断$x$这个数字到底是含有奇数个$1$,另外一个数字含有偶数个$1$.

​     接下来的问题就转化为线段的并了,我们可以很方便的用主席树来解决。

​     对值域建动态开点的线段树,当前区间如果被覆盖了直接打上一个$vis$标记,下一次不覆盖当前区间即可。

​     设数的值域是$S$,那么这样做的时间复杂度是$O(n log_2S)$

# pragma GCC optimize()
# include <bits/stdc++.h>
# define int long long
# define lowbit(x) (x&(-x))
const int N=1e5+;
using namespace std;
int n,tot;
inline int read() {
int X=,w=; char c=;
while(c<''||c>'') {w|=c=='-';c=getchar();}
while(c>=''&&c<='') X=(X<<)+(X<<)+(c^),c=getchar();
return w?-X:X;
}
void write(int x) {
if (x<) x=-x,putchar('-');
if (x>) write(x/);
putchar(''+x%);
}
int query(int x) {
if (x&) return x/+;
int ret=,res=x/;
while (x) { x-=lowbit(x); ret^=;}
return res+ret;
}
bool vis[N*];
struct Seg {
int ls,rs,cnt1,cnt2;
}tr[N*];
# define ls tr[x].ls
# define rs tr[x].rs
void update(int &x,int l,int r,int opl,int opr) {
if (!x) x=++tot; if (vis[x]) return;
if (opl<=l && r<=opr) {
vis[x]=;
tr[x].cnt1=query(r)-query(l-);
tr[x].cnt2=r-l+-tr[x].cnt1;
return;
}
int mid=(l+r)>>;
if (opl<=mid) update(ls,l,mid,opl,opr);
if (opr>mid) update(rs,mid+,r,opl,opr);
tr[x].cnt1=tr[ls].cnt1+tr[rs].cnt1;
tr[x].cnt2=tr[ls].cnt2+tr[rs].cnt2;
}
signed main() {
n=read();
int root=;
for (int i=;i<=n;i++) {
int l=read(),r=read();
update(root,,(1ll<<)-,l,r);
write(tr[].cnt1*tr[].cnt2);
putchar('\n');
}
return ;
}

sequence.cpp

Problem C 钢琴家

给出一个基本字符串$S$,给出$n$个目标字符串集合$t_i$。

要求修改一些$S_i$使得可以将$S$划分成一些子串,使得这些子串都在目标字符串集合中出现。

让替换次数尽可能小,且保证存在至少一个最优解。

对于$100\%$的数据,满足 $1 \leq |t_i| \leq |S|\leq 10^3 , 1\leq n\leq 10^2​$

​ Solution :

  本题可以直接用$DP$求出最优策略,设$f[i]$表示匹配到长度$i$的最小代价。

​   枚举一个目标字符串$1 \leq j \leq n$,可以考虑$[i-|t_j|+1 , i]$用串$t_j$来修改。

​   然后计算这样做的代价,就是$\sum\limits_{k = 1}^{|t_j|} [\ S[i-|t_j|+k]\neq t_j[k]\ ]$

​   记录每一次最优的转移是从何而来,这样可以输出方案。

​   最后直接按照最优方案输出即可。

​   时间复杂度为$O(n|S|^2)$

# pragma GCC optimize()
# include <bits/stdc++.h>
using namespace std;
const int N=1e3+;
char t[N][N],s[N];
int n,f[N],len[N];
int pre[N];
int ans[N];
int main() {
scanf("%s",s+);int l=strlen(s+);
scanf("%d",&n);
for (int i=;i<=n;i++) {
scanf("%s",t[i]+);
len[i]=strlen(t[i]+);
}
memset(f,0x3f,sizeof(f)); f[]=;
for (int i=;i<=l;i++)
for (int j=;j<=n;j++) if (i>=len[j]){
int res = ;
for (int k=;k<=len[j];k++) {
if (t[j][k]!=s[i-len[j]+k]) res++;
}
if (f[i-len[j]]+res<f[i]) {
f[i] = f[i-len[j]]+res;
pre[i] = j;
}
}
int now = l;
while (true) {
if (now == ) break;
ans[++ans[]] = pre[now];
now=now-len[pre[now]];
}
for (int i=ans[];i>=;i--) {
for (int j=;j<=len[ans[i]];j++)
putchar(t[ans[i]][j]);
putchar('\n');
}
return ;
}

pianist.cpp

HGOI 20191106 题解的更多相关文章

  1. HGOI 20191106

    HGOI 20191106 t1 旅行家(traveller) 2s,256MB [题目背景] 小X热爱旅行,他梦想有一天可以环游全世界-- [题目描述] 现在小X拥有n种一次性空间转移装置,每种装置 ...

  2. HGOI 20181028 题解

    HGOI 20181028(复赛备考) /* 真是暴力的一天,最后一题MLE?由于数组开得太大了!!! 270滚粗 考场上好像智商高了很多?!(假的) */ sol:暴力求解,然后没有数据范围吐槽一下 ...

  3. HGOI 20190310 题解

    /* 又是又双叒叕WA的一天... 我太弱鸡了... 今天上午打了4道CF */ Problem 1 meaning 给出q组询问,求下列函数的值$ f(a) = \max\limits_{0 < ...

  4. HGOI 20190303 题解

    /* 记一串数字真难. 5435 今天比赛又是hjcAK的一天. 今天开题顺序是312,在搞T1之前搞了T3 昨天某谷月赛真是毒瘤. 但是讲评的同学不错,起码T4看懂了... 构造最优状态然后DP的思 ...

  5. HGOI 20180224 题解

    /* The Most Important Things: ljc chat with fyh on QQTa说期末考Ta数学74分感觉不好但是我觉得fyh是地表最强的鸭~~(of course en ...

  6. HGOI 20190218 题解

    /* 又是AK局... hjc又双叒叕AK了... Hmmm...我侥幸 */ Problem A card 给出无序序列a[]可以选择一个数插入到合适的位置作为一次操作,至少多少次操作后可以把序列变 ...

  7. HGOI 20190217 题解

    /* for me,开训第一天 /beacuse 文化课太差被抓去补文化课了... 看一眼题 : AK局? 但是,Wa on test #10 in problem C 290! (就差那么一咪咪) ...

  8. HGOI 20181103 题解

    problem:把一个可重集分成两个互异的不为空集合,两个集合里面的数相乘的gcd为1(将集合中所有元素的质因数没有交集) solution:显然本题并不是那么容易啊!考场上想了好久.. 其实转化为上 ...

  9. HGOI 20181101题解

    /* 又是爆0的一天(不知道今年高考难不难,反正今天(信息学)真的难!) */ solution:对于两个数相加,有一个显然的结论就是要么不进位(相对于位数大的),要么(进最多一位) 然后对于整个数组 ...

随机推荐

  1. 利用Python进行数据分析_Numpy_基础_1

    ndarray:多维数组 ndarray 每个数组元素必须是相同类型,每个数组都有shape和dtype对象. shape 表示数组大小 dtype 表示数组数据类型 array 如何创建一个数组? ...

  2. 异常:Invalid character found in the request target. The valid characters are defined in RFC 3986

    一.背景 事情是这样的,前几天做一个基本的数据库“增删改查”的需求,前端传参的方式是“JSON字符串”,后端接收到此参数后,使用阿里巴巴fastjson进行解析,然后入库.需求很简单吧,但是偏偏遇到问 ...

  3. ECMAScript中的原型继承

    //ECMAScript中的原型继承//ECMAScript中的继承主要是依靠原型链实现的.(关于原型链的介绍,详见<高三>6.3.1章节 P162) //本文示例主要为了说明SubTyp ...

  4. 前端性能优化-Vue代码层面

    1.v-if 和 v-show 区分使用场景 v-if 是 真正 的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建:也是惰性的:如果在初始渲染时条件为假,则什么也不做 ...

  5. web储存的初级运用

    <html> <head> <meta charset="utf-8"> <title>web存储</title>< ...

  6. CSS精灵技术(sprite)

    CSS技术的使用场景:有效的减少了服务器接收和发送请求的次数,css精灵是一种出来网页背景图像的方式,将一个页面设计到的所有零星背景图集中到一张大图中去,然后将大图应用于网页 .通过backgroun ...

  7. C# webserver实现短信发送(移动)

    近端时间接了个需求在原来的OA办公系统中添加一个发送短信功能.(既然需要发送短信那肯定要申请一个发送短信的账号,我这里是以移动mas为列子) c#的weserver需要选协议WS.其他的基本不用怎么填 ...

  8. 第一篇.markdown

    目录 Day 01 1.markdown的使用感受 2.markdown的基本语法 2.1 标题 2.2 加粗 2.3 斜体 2.4 高亮 2.5 上标 2.6 下标 2.7 代码引用(>式) ...

  9. Python 内置函数进制转换的用法(十进制转二进制、八进制、十六进制)

    ↓ 2进制 8进制 10进制 16进制 2进制 - bin(int(x, 8)) bin(int(x, 10)) bin(int(x, 16)) 8进制 oct(int(x, 2)) - oct(in ...

  10. java——多线程并发库

    JDK5中增加了Doug Lea的并发库,这一引进给Java线程的管理和使用提供了强大的便利性. java.util.current包中提供了对线程优化.管理的各项操作,使得线程的使用变得的心应手.该 ...