好吧,由于赛时本人还是一个蒟蒻,(虽然现在也是),导致一直没有做完后面两题。。。
先说下赛时分数吧。。。
前两题日常水过,后两题日常放弃,其实第三题有想着做但是没时间了
第一题 | 第二题 | 第三题 | 第四题 |
---|---|---|---|
Accepted | Accepted | WA | WA |
。。。
https://www.luogu.org/recordnew/lists?uid=52915&pid=3954
输入 a,b,c a , b , c 计算 a∗0.2+b∗0.3+c∗0.5 a ∗ 0.2 + b ∗ 0.3 + c ∗ 0.5
模拟,由于 C++ C + + 的强制转换很骚,所以就要注意一下
时间复杂度和空间复杂度都是 O(1) O ( 1 )
#include
#define sr c=getchar()
#define input read()
#define pd (c<'0'||c>'9')
using namespace std;
int read()//楼楼超丑的代码,莫介意
{
int d=1,f=0;char c;
while (sr,pd) if (c=='-') d=-1;f=f*10+c-48;
while (sr,!pd) f=f*10+c-48;
return d*f;
}
int main()
{
int x,y,z;
x=input;y=input;z=input;
int a,b,c;
a=x*20;b=y*30;c=z*50;
int ans=(a+b+c)/100;
printf("%d",ans);//防止强制转换出现的bug
}
https://www.luogu.org/recordnew/lists?uid=52915&pid=3955
忘了(真的忘了。。。,真的不是我懒)
重点在%,模拟,本人代码奇丑无比,奇low无比(当时是真的蒟蒻)
时间复杂度: O(nlogn+m(nleni+∑len)) O ( n l o g n + m ( n l e n i + ∑ l e n ) )
空间复杂度: O(2n+m) O ( 2 n + m )
(丑到怀疑人生)
#include
#include
#include
#include
#define sr c=getchar()
#define input read()
#define pd (c<'0'||c>'9')
using namespace std;
int n,m;
int book[1011]; int z[1011];
int numb[111];//一群丑数组
int len;
bool ok;
bool cmp(int x,int y)//一个丑排序
{
return xbool pds(int x)//一个丑判断
{
int j=0;
while (x>0)
{
j++;
z[j]=x%10;
x/=10;
//printf("%d",z[j]);
}
int i=0;
if (len>j) return false;
for (int k=len;k>0;k--)
{
i++;
if (z[i]!=numb[k]) return false;
}
return true;
}
int read()//一个丑输入流
{
char c;int d=1,f=0;
while (sr,pd) if (c=='-') d=-1;f=f*10+c-48;
while (sr,!pd) f=f*10+c-48;
return d*f;
}
int main()
{
n=input;m=input;
for (int i=1;i<=n;i++)
book[i]=input;//一个丑输入
sort(book+1,book+1+n,cmp);//丑排序
for (int i=1;i<=m;i++)
{
len=input;char lc;//memset(numb,0,sizeof(numb));
for (int j=1;j<=len;j++)
{
lc=getchar();
numb[j]=lc-48;
}ok=false;//丑输入
for (int j=1;j<=n;j++)
{
if (pds(book[j])) {ok=true;printf("%d\n",book[j]);break;}//丑查找
}
if (!ok) printf("-1\n");//丑判断
}
return 0;//丑return
}
终于丑完了
https://www.luogu.org/recordnew/lists?uid=52915&pid=3956
有一个 n×n n × n 的棋盘,有 m m 个色块是有色的。
有色的色块间有两种规则
可以施展膜拜大法(魔法),将无色的方格变成有色的方格的颜色,代价为2
现求从左上角走到右下角的最小花费,若不能到达,输出-1
暴搜会超时,解法很多,这里列举一下
最短路(这个很复杂,洛谷上有详细介绍,这里主要讲dfs)
其实dfs很容易理解,就是开一个 use u s e 表示是否有使用魔法,也可以直接在 dfs d f s 里面加一个 flag f l a g 来判断,效果是一样的
值得注意的是,走过的路还能再走,所以不用判断是否已经走过,而是保存最优解
时间复杂度: O(n2) O ( n 2 ) (应该是吧)
空间复杂度: O(3n2) O ( 3 n 2 ) (若使用flag作为一个参数,空间复杂度可一将为 O(2n2) O ( 2 n 2 ) )
终于不是奇丑无比了,当然在 dalao d a l a o 面前永远是丑的。。。
// luogu-judger-enable-o2
#include
#include
#include
#define LL long long
#define r(i,a,b) for(int i=a;i<=b;i++)
#define check(x,y) (x>=1&&x<=n&&y>=1&&y<=n)//判断是否在期盼内
using namespace std;int n,m,ans=536870912;
const short dx[4]={-1,0,1,0};
const short dy[4]={0,1,0,-1};//四个方向
bool use[101][101];int color[101][101],f[101][101];//use为是否使用魔法,color表示此点的颜色,f表示最优解
LL read()//输入流
{
char c;int f=0,d=1;
while((c=getchar())<48||c>57)if(c=='-')d=-1;f=(f<<3)+(f<<1)+c-48;
while((c=getchar())>=48&&c<=57)f=(f<<3)+(f<<1)+c-48;
return d*f;
}
void dfs(int x,int y,int now)
{
if(!check(x,y)||now>=f[x][y]) return;//超出范围或者不是最优则退出
if(x==n&&y==n) {ans=min(now,ans);return;}f[x][y]=now;//保存
r(i,0,3)
{
int qx=x+dx[i],qy=y+dy[i];//获取位置
if(check(qx,qy))//判断
{
if(use[x][y]&&!color[qx][qy]) continue;//若已经使用魔法但是目标格子是空的那么直接返回
if(color[qx][qy])
if(color[x][y]==color[qx][qy]) dfs(qx,qy,now);//颜色相同
else dfs(qx,qy,now+1);//不相同
else
if(!use[x][y]&&!color[qx][qy])//使用魔法
{
use[qx][qy]=true;
color[qx][qy]=color[x][y];//标记已经使用并且改变颜色
dfs(qx,qy,now+2);
use[qx][qy]=false;
color[qx][qy]=0;//回溯
}
}
}
}
int main()
{
memset(f,127/3,sizeof(f));
n=read();m=read();
r(i,1,m) color[read()][read()]=read()+1;//输入,为了更好区分,所以每个格子都+1,这样区分开了红色和白色的格子
dfs(1,1,0);//搜索
if(ans==536870912) puts("-1");else printf("%d",ans);//输出
}
https://www.luogu.org/problemnew/show/P3957
在一根数轴上有 n n 个点,给出它们距离原点的距离以及它们的价值,现在有一个机器人,他每次可以向右边走 d d 个单位长度,但是为了的得到一定的价值 k k ,需要改进这个机器人。已知花费 g g 点金币可以使它能跳的距离变成
max(1,d−g)...g+d m a x ( 1 , d − g ) . . . g + d 之间,问至少需要多少金币可以拿到 k k 点价值
首先可以想到若使用 g g 枚金币可以,那么使用 g+1 g + 1 枚也必然可以,所以这就满足二分的条件
至于如何确定二分的答案是否正确呢?需要用到动态规划,先给出方程
#include
#include
#include
#define LL long long
#define r(i,a,b) for(int i=a;i<=b;i++)
#define N 500001
using namespace std;LL n,d,k,l,r,mid,far[N],num[N],ans=-1,dp[N];
LL read()
{
char c;int f=0,d=1;
while((c=getchar())<48||c>57)if(c=='-')d=-1;f=(f<<3)+(f<<1)+c-48;
while((c=getchar())>=48&&c<=57)f=(f<<3)+(f<<1)+c-48;
return d*f;
}
bool check(int money)
{
deque<int>q;
far[0]=0;
fill(dp,dp+n,0);//初始化
int high=money+d,low=max(d-money,(LL)1);//记得末尾是1
int j=0;
r(i,1,n)
{
while(far[i]-far[j]>=low)
{
while(!q.empty()&&dp[j]>=dp[q.back()]) q.pop_back();//弹出去
q.push_back(j++);//放进来
}
while(!q.empty()&&far[i]-far[q.front()]>high) q.pop_front();//弹出去
if(q.empty())dp[i]=-9999999999;//空了
else dp[i]=dp[q.front()]+num[i];//没空
if(dp[i]>=k) return 1;//判断
}
return 0;
}
int main()
{
n=read();d=read();k=read();
r(i,1,n)
far[i]=read(),num[i]=read();
int l=1,r=N<<5;//范围
while(l<=r)
{
mid=(l+r)>>1;
if(check(mid)) ans=mid,r=mid-1;else l=mid+1;//二分
}
printf("%lld",ans);
}
#include
#include
#define LL long long
#define r(i,a,b) for(int i=a;i<=b;i++)
#define N 500001
using namespace std;LL n,d,k,l,r,mid,far[N],num[N],ans=-1,dp[N];
LL read()
{
char c;int f=0,d=1;
while((c=getchar())<48||c>57)if(c=='-')d=-1;f=(f<<3)+(f<<1)+c-48;
while((c=getchar())>=48&&c<=57)f=(f<<3)+(f<<1)+c-48;
return d*f;
}
bool check(int money)//方法和上面是一样的
{
int q[N]={0};
fill(dp,dp+n,-1);dp[0]=0;
int high=money+d,low=max(d-money,(LL)1);
int j=0,head=1,tail=0;
r(i,1,n)
{
while(far[i]-far[j]>=low)
{
while(head<=tail&&dp[j]>=dp[q[tail]]) tail--;
q[++tail]=j++;
}
while(head<=tail&&far[i]-far[q[head]]>high) head++;
if(head<=tail)dp[i]=dp[q[head]]+num[i];else dp[i]=-9999999999;
if(dp[i]>=k) return 1;
}
return 0;
}
int main()
{
n=read();d=read();k=read();
r(i,1,n)
far[i]=read(),num[i]=read();
int l=1,r=far[n];
while(l<=r)
{
mid=(l+r)>>1;
if(check(mid)) ans=mid,r=mid-1;else l=mid+1;//二分
}
printf("%lld",ans);//输出
}