Day 1, Div 2, Prob. B - 吃豆豆

题目大意

wls有一个\(n\)行\(m\)列的棋盘,对于第\(i\)行第\(j\)列的格子,每过\(T[i][j]\)秒会在上面出现一个糖果,糖果只存在一秒,下一秒就会消失。

假如wls第\(k\)秒在第\(i\)行第\(j\)列的格子上,满足\(T[i][j]|k\),则wls会得到一个糖果。

wls每一秒只可以上下左右移动一格或停在原地。

请问wls从指定的\(S(xs,ys)​\)出发到达指定的\(T(xt,yt)​\),并且在路上得到至少\(C​\)个糖果最少需要多少时间?

wls在\(S\)的初始时间是第0秒。

\[1\leq n,m,T[i][j]\leq 10; 1\leq C\leq 1018
\]

解题思路

\(dp[i][j][k]\)表示吃到至少\(k\)颗豆豆,并且停在\((i,j)\)处的最少时间(“最少”其实有些不准确,这个后面再解释)。那么\(dp[i][j][1]\)就可以这样求出来了:

\[dp[i][j][1]=dist(xs,ys,i,j)+\Delta t
\]

\(\Delta t\)主要用于对\(T[i][j]\)取整,注意\(dp[xs][ys][1]\)就等于\(T[xs][ys]\)。接下来可以递推求\(dp[i][j][k]\)了:

\[dp[i][j][k]=min\{dp[i'][j'][k-1]+dis(i',j',i,j)+\Delta t\}
\]

同样\((i',j')\)和\((i,j)\)相同时也要特殊考虑。

所以重新说明一下\(dp[i][j][k]\)的意义。它表示吃到至少\(k\)颗豆豆,并且停在\((i,j)\)的某个时间。这个时间满足:给定\(k\),由所有的\(dp[i'][j'][k]\)走到\((i,j)\),取最小值就是至少吃\(k\)颗豆豆,并且停在\((i,j)\)处的最少时间。因为由\(dp[i'][j'][k-1]\)转移到\(dp[i][j][k]\)时,路途上可能吃了豆豆,但这一定也会被某个\(dp[i''][j''][k]\)存储起来。

还是有点难理解,\(dp\)的题还是要多做一些才能有这样的思路。

#include <bits/stdc++.h>

typedef long long ll;
const int inf=0x3f3f3f3f;
const double eps=1e-5;
const int mod=1000000007;
const int maxn=10;
const int maxm=1018; using namespace std; int t[maxn+5][maxn+5];
int dp[maxn+5][maxn+5][maxm+10]; int dist(int x1,int y1,int x2,int y2)
{
return abs(x1-x2)+abs(y1-y2);
} int main()
{
int n,m,c;
scanf("%d%d%d",&n,&m,&c);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",t[i]+j);
int xs,ys,xt,yt;
scanf("%d%d%d%d",&xs,&ys,&xt,&yt); memset(dp,0x3f,sizeof(dp));
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(i!=xs||j!=ys)
dp[i][j][1]=(dist(xs,ys,i,j)+t[i][j]-1)/t[i][j]*t[i][j];
else
dp[i][j][1]=t[i][j];
} for(int k=2;k<=c;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int ii=1;ii<=n;ii++)
for(int jj=1;jj<=m;jj++)
{
int temp;
if(ii==i&&jj==j)
temp=dp[ii][jj][k-1]+t[ii][jj];
else
temp=(dp[ii][jj][k-1]+dist(ii,jj,i,j)+t[i][j]-1)/t[i][j]*t[i][j];
dp[i][j][k]=min(dp[i][j][k],temp);
} int ans=inf;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
int temp=dp[i][j][c]+dist(i,j,xt,yt);
ans=min(ans,temp);
}
} printf("%d\n",ans); return 0;
}

Day 4, Div 2, Prob. G - 置置置换

题目大意

wls有一个整数\(n\),他想请你算一下有多少\(1...n\)的排列(permutation)满足:对于所有的\(i(2\leq i\leq n)\),若\(i\)为奇数,则\(a[i-1]<a[i]\),否则\(a[i-1]>a[i]\)。请输出答案mod 1e9+7。

\[1\leq n\leq 1000
\]

解题思路

\(dp[i][j]\)表示使用\(1...i\),开头为\(j\)的符合条件的排列数。

容易发现,将\(dp[i][j]\)排列对\(i+1\)取补,在开头加上一个比\(i+1-j\)大的数\(j'\),再把不比\(j'\)小的数都加一,就构造了一个新的\(1...i+1\)的排列。转移方程如下:

\[dp[i][j]=\sum\limits _{j'=i-j+1}^{i-1} dp[i-1][j']
\]

容易发现,给定\(j\),这样构造是不重不漏的:每个\(dp[i][j]\),都可以有一个\(dp[i-1][j']\)与之对应;而每个\(dp[i-1][j']\),都可以对指定的\(j\),构造出一个\(dp[i][j]\)。

再利用一个前缀和,将复杂度降到\(O(n^2)\)。

#include <bits/stdc++.h>

typedef long long ll;
const int inf=0x3f3f3f3f;
const double eps=1e-5;
const int mod=1000000007;
const int maxn=1000;
const int maxm=300000; using namespace std; ll dp[maxn+10][maxn+10]; int main()
{
int n;
scanf("%d",&n); memset(dp,0,sizeof(dp));
dp[1][1]=1;
for(int i=2;i<=n;i++)
{
for(int j=1;j<=i;j++)
{
dp[i][j]=(dp[i-1][i-1]-dp[i-1][i-j])%mod;
}
for(int j=1;j<=i;j++)
dp[i][j]=(dp[i][j]+dp[i][j-1])%mod;
} printf("%lld\n",(dp[n][n]%mod+mod)%mod); return 0;
}

Day 5, Div 2, Prob. F - Kropki

题目大意

你有一个\(1\)到\(n\)的排列 \(p_1\), \(p_2\), ... , \(p_n\),对于所有的\(i(1\leq i\leq n-1)\), 如果\(p_i\)和\(p_{i+1}\)中,有一个数是另一个数的两倍,那么这两个数之间标一个1,否则标0。

给定及长度为\(n-1(2\leq n\leq 15)\)的01串\(str[1:n-1]\),问有多少\(1\)到\(n\)的排列对应该01串。

解题思路

状压DP。\(dp[i][j][k]​\)表示\(1...i​\)位,使用过的数字状态是\(j​\),末位是\(k​\)的排列数。

当\(i​\)与\(i+1​\)之间标1时,若\(k\times 2\leq n​\)且未被使用,则\(dp[i][j][k]​\)可以向\(dp[i+1][j'][k\times 2]​\)转移:

\[dp[i+1][j|(1<<(2k-1))][2k]+=dp[i][j][k],str[i]==1,2k\leq n,j\&(1<<(2k-1))==0
\]

同理可得:

\[dp[i+1][j|(1<<(k/2-1))][k/2]+=dp[i][j][k],str[i]==1,k\%2==0,j\&(1<<(k/2-1))==0
\]

\[dp[i+1][j|(1<<(tmp-1))][tmp]+=dp[i][j][k],str[i]==0,1\leq tmp\leq n,k\%2==1||tmp\neq k/2,tmp\neq 2k,j\&(1<<(tmp-1))==0​
\]

#include<bits/stdc++.h>

typedef long long ll;
const int inf=0x3f3f3f3f;
const double eps=1e-5;
const double pi=3.141592653589793;
const int mod=1000000007;
const int maxn=1000;
const int maxm=1000; using namespace std; char str[maxn+10];
int dp[20][40000][20]; int main()
{
int n;
scanf("%d",&n);
scanf("%s",str+1); memset(dp,0,sizeof(dp));
for(int i=1; i<=15; i++)
dp[1][1<<(i-1)][i]=1; for(int i=1; i<=n-1; i++)
for(int j=1;j<=(1<<n)-1;j++)
for(int k=1;k<=n;k++)
if(dp[i][j][k]>0)
{
if(str[i]=='1')
{
if(k%2==0&&(j&(1<<((k/2)-1)))==0)
dp[i+1][j|(1<<((k/2)-1))][k/2]=(dp[i+1][j|(1<<((k/2)-1))][k/2]+dp[i][j][k])%mod;
if(k*2<=n&&(j&(1<<((k*2)-1)))==0)
dp[i+1][j|(1<<((k*2)-1))][k*2]=(dp[i+1][j|(1<<((k*2)-1))][k*2]+dp[i][j][k])%mod;
}
else
{
for(int tmp=1;tmp<=n;tmp++)
if((k%2==1||tmp!=k/2)&&tmp!=k*2&&(j&(1<<((tmp)-1)))==0)
dp[i+1][j|(1<<((tmp)-1))][tmp]=(dp[i+1][j|(1<<((tmp)-1))][tmp]+dp[i][j][k])%mod;
}
}
ll ans=0;
for(int i=1;i<=n;i++)
ans=(ans+1LL*dp[n][(1<<n)-1][i])%mod;
printf("%lld\n",ans); return 0;
}

CCPC Wannafly Winter Camp Div2 部分题解的更多相关文章

  1. 2020 CCPC Wannafly Winter Camp Day1 C. 染色图

    2020 CCPC Wannafly Winter Camp Day1 C. 染色图 定义一张无向图 G=⟨V,E⟩ 是 k 可染色的当且仅当存在函数 f:V↦{1,2,⋯,k} 满足对于 G 中的任 ...

  2. 2020 CCPC Wannafly Winter Camp Day1-F-乘法

    题目传送门 sol:二分答案$K$,算大于$K$的乘积有多少个.关键在于怎么算这个个数,官方题解上给出的复杂度是$O(nlogn)$,那么计算个数的复杂度是$O(n)$的.感觉写着有点困难,自己写了一 ...

  3. 2020 CCPC Wannafly Winter Camp Day1 Div.1&amp F

    #include<bits/stdc++.h> #define forn(i, n) for (int i = 0; i < int(n); i++) #define fore(i, ...

  4. 2020 CCPC Wannafly Winter Camp Day1 - I. K小数查询(分块)

    题目链接:K小数查询 题意:给你一个长度为$n$序列$A$,有$m$个操作,操作分为两种: 输入$x,y,c$,表示对$i\in[x,y] $,令$A_{i}=min(A_{i},c)$ 输入$x,y ...

  5. 2020 CCPC Wannafly Winter Camp Day2-K-破忒头的匿名信

    题目传送门 sol:先通过AC自动机构建字典,用$dp[i]$表示长串前$i$位的最小代价,若有一个单词$s$是长串的前$i$项的后缀,那么可以用$dp[i - len(s)] + val(s)$转移 ...

  6. 2019 wannafly winter camp day 3

    2019 wannafly winter camp day 3 J 操作S等价于将S串取反,然后依次遍历取反后的串,每次加入新字符a,当前的串是T,那么这次操作之后的串就是TaT.这是第一次转化. 涉 ...

  7. 2019 wannafly winter camp

    2019 wannafly winter camp Name Rank Solved A B C D E F G H I J K day1 9 5/11 O O O O O day2 5 3/11 O ...

  8. CCPC、Petrozavodsk Camp、OpenCup 题解汇总

    省赛 \([\text{2021.11.30}]\) 2021 Jilin Collegiate Programming Contest 全部完成. \([\text{2021.12.25}]\) 2 ...

  9. 2019 wannafly winter camp day5-8代码库

    目录 day5 5H div2 Nested Tree (树形dp) 5F div2 Kropki (状压dp) 5J div1 Special Judge (计算几何) 5I div1 Sortin ...

随机推荐

  1. 在input输入值改变reducer里的值

    输入值改变reducer里的值 通过store.dispatch传入reducer中,函数的第二个参数可以接收到 在reducer中 在todolist文件中 然后在把this.state中的值改变

  2. centos7 设置连接无线wifi

    安装系统后,首先要联网. 1.首先使用网线连接,之后尝试ping www.baidu.com我的是自动通的 2.需要查看网卡型号,先安装工具 yum -y install pciutils* 3.查看 ...

  3. centos7清理矿机木马qw3xT,kpgrbcc

    腾讯云报告了root口令被暴力破解,并种了木马kpgrbcc 昨晚找到/usr/bin/ rm -rf kpgrbcc 删除 rm -rf kpgrbcb 删除 并ps -ef | grep kpg ...

  4. ubuntu 16.04源码编译OpenCV教程 | compile opencv on ubuntu 16.04

    本文首发于个人博客https://kezunlin.me/post/15f5c3e8/,欢迎阅读! compile opencv on ubuntu 16.04 Series Part 1: comp ...

  5. SpringBoot 源码解析 (九)----- Spring Boot的核心能力 - 整合Mybatis

    本篇我们在SpringBoot中整合Mybatis这个orm框架,毕竟分析一下其自动配置的源码,我们先来回顾一下以前Spring中是如何整合Mybatis的,大家可以看看我这篇文章Mybaits 源码 ...

  6. 【集训Day1 测试】装饰

    装饰(decorate) [题目描述] 一个图有 N 个结点,编号 1 至 N,有 M 条无向边,第 i 条边连接的两个结点是 Ai 和Bi,其中 Ai 和 Bi 是不同的结点.可能有多条边连接的是同 ...

  7. 转帖:30多条mysql数据库优化方法,千万级数据库记录查询轻松解决

    地址:http://www.ihref.com/read-16422.html

  8. 重新调用 layoutSubview

    重新调用 layoutSubview

  9. WebGL简易教程(十四):阴影

    目录 1. 概述 2. 示例 2.1. 着色器部分 2.1.1. 帧缓存着色器 2.1.2. 颜色缓存着色器 2.2. 绘制部分 2.2.1. 整体结构 2.2.2. 具体改动 3. 结果 4. 参考 ...

  10. js对象可扩展性和属性的四个特性(上)

    # js对象可扩展性和属性的四个特性(上) 一.前言 再次花时间回顾一下基础,毕竟要想楼建的好,地基就要牢固,嘻嘻! 在开始之前需要具备对prototype.__proto__.constructor ...