Test 2022.09.27
今天不知道是什么专场了,但是我知道的是我今天真的没有改完!!!!太气了,最短路的赋值号写成大于竟然不会报错,害得我改了半个下午一个晚上,lz快要崩溃了
T1 Windy数
简简单单数位dp,但是我一测的时候好像打了一个bug,不知道在哪,wa掉了一个点,后面交了一遍之前的代码,就过了,思路就是定义\(dp[i][j]\)为长度为\(i\)位的数,且最高位是\(j\)的满足条件的数的数量,转移方程懒得写\(LaTeX\)的大括号了,今天实在是时间不够了,就直接上代码
点击查看代码
void pre()
{
for(int i=0;i<=9;i++)
dp[1][i]=1;
for(int i=2;i<=10;i++)
{
for(int j=0;j<=9;j++)
{
for(int k=0;k<=9;k++)
{
if(abs(j-k)>=2) dp[i][j]+=dp[i-1][k];
}
}
}//dp[i][j]只会在前面有数并要拼上去时才会用到,因为计算时考虑了前导0对后面的影响
}
然后数位\(dp\)统计答案一直都是一个难点,注释都在代码里面了
点击查看代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
bool check(int x,int y)
{
return abs(x-y)>=2?1:0;
}
int dp[15][15];int a[15];int d,t;int s[15];
void pre()
{
for(int i=0;i<=9;i++)
dp[1][i]=1;
for(int i=2;i<=10;i++)
{
for(int j=0;j<=9;j++)
{
for(int k=0;k<=9;k++)
{
if(abs(j-k)>=2) dp[i][j]+=dp[i-1][k];
}
}
}//dp[i][j]只会在前面有数并要拼上去时才会用到,因为计算时考虑了前导0对后面的影响
}
long long calc(int x)
{
memset(a,0,sizeof a);
int cnt=0;long long ans=0;
do
{
a[++cnt]=x%10;
x/=10;
}while(x);
for(int i=1;i<=cnt-1;i++)
{
for(int j=1;j<=9;j++)
ans+=dp[i][j];
}//所有位数不足cnt的情况
for(int i=1;i<a[cnt];i++)
ans+=dp[cnt][i];
//位数为cnt但是最高位小于a【cnt】的情况
for(int i=cnt-1;i>=1;i--)
{
if(i==1&&check(a[i],a[i+1]))
ans++;
for(int j=0;j<a[i];j++)
{
if (check(j,a[i+1]))
ans+=dp[i][j];
}
if(!check(a[i],a[i+1]))break;/*当前不满足后面就不可能*/
}
return ans;
}
int main()
{
scanf("%d%d",&d,&t);
pre();
// for(int i=0;i<=50;i++)
// {
// printf("calc(%d):%d\n",i,calc(i));
// }
// for(int i=1;i<=3;i++)
// {
// for(int j=0;j<=9;j++)
// printf("dp[%d][%d]:%d\n",i,j,dp[i][j]);
// }
// printf("%d\n",calc(t));
printf("%lld",calc(t)-calc(d-1));
return 0;
}
T2 生日快乐
本来以为是个结论题,于是自己乱整了几组数据,发现要尽量分的平均,于是就有了以下代码
点击查看代码
#include<cstdio>
#include<algorithm>
#include<cstdlib>
using namespace std;
void swap1(double &x,double &y){double tmp=x;x=y;y=tmp;}
int main()
{
double x,y,n;
scanf("%lf%lf%lf",&x,&y,&n);
double ans1=-1,ans2=-1;
int div1=(int)n/2,div2=(int)n-div1;
double tmp1=1.0*div1/(div1+div2)*x,tmp2=y/(1.0*div1);
if(tmp1<tmp2)swap1(tmp1,tmp2);
ans1=max(ans1,tmp1/tmp2);
tmp1=1.0*div2/(div1+div2)*x,tmp2=y/(1.0*div2);
if(tmp1<tmp2)swap1(tmp1,tmp2);
ans1=max(ans1,tmp1/tmp2);
////////////////
tmp1=1.0*div1/(div1+div2)*y,tmp2=x/(1.0*div1);
if(tmp1<tmp2)swap1(tmp1,tmp2);
ans2=max(ans2,tmp1/tmp2);
tmp1=1.0*div2/(div1+div2)*y,tmp2=x/(1.0*div2);
if(tmp1<tmp2)swap1(tmp1,tmp2);
ans2=max(ans2,tmp1/tmp2);
printf("%.6lf",min(ans1,ans2));
return 0;
}
点击查看代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
using namespace std;
double dfs(double x,double y,double n)
{
if(n==1)return 1.0*max(x,y)/min(x,y);
double tmp=1145141919;double divide_x=x*1.0/n,divide_y=y*1.0/n;
for(int i=1;i<=n/2;i++)
{
tmp=min(tmp,max(dfs(divide_x*i,y,i),dfs(x-divide_x*i,y,n-i)));
tmp=min(tmp,max(dfs(x,divide_y*i,i),dfs(x,y-divide_y*i,n-i)));
}
return tmp;
}
int main()
{
// freopen("happy.in","r",stdin);
// freopen("happy.out","w",stdout);
double x,y,n;
scanf("%lf%lf%lf",&x,&y,&n);
printf("%.6lf",dfs(x,y,n));
return 0;
}
其中\(dfs\)的三个参数分别为:当前的两条边、当前需要分的块数量。
你可能会问这样怎么保证最后的面积相等??我也有过这种问题,后来想明白了。
由于\(dfs\)的特性,在\(n/2==1\)的时候,当前这一层的\(dfs\)都会把最后剩下要分的部分分成相等的两块,总的来看,所有的\(dfs\)操作最后把整个蛋糕分成了相等的\(n\)块,也就是\(S=x*y/n\),那么我们理解了这一点之后按着题意来就行了
T3 最长距离 最气的题(不肯抄题解的倔强
当时以为正解是暴力枚举每个障碍物是否存在,再加一些小小的优化,没想到最短路,受教了,这道题也的的确确让我意识到最短路完全不用去解决纯的边权和最小问题,而是可以通过转化一些状态,再建立相应的边,通过最短路的算法来计算最小代价(言下之意就是抽象化了)
这道题最重要的地方就是!!:定义\(dis[i][j]\)为从当前点到\(i,j\)所需要\(\huge 移除的最少障碍量\)
这之后就是对于每一个图上的点跑一边\(spfa\),然后用一个\(record[i][j]\)数组记录当前状态到所有点的\(dis\)这里面有很多小细节,本人坑踩得足足的。
\(\huge 警钟敲烂\),为了防止以后成傻逼,不惜时间成本一一列举犯傻的点
\(First\)
硬要用一种脑瘫\(hash\)方式来映射每一个点,没想到会很轻易地挂掉,因为在计算哈希的时候并不是双向的,用模运算的时候可能为\(0\),就直接\(g\)掉,以及一些边界情况都会出问题!!
点击查看代码
int calc(int x,int y){return m*(x-1)+y;}
void code(int &x,int &y,int t)
{
x=t/m+1;
y=x%m;
}
\(Second\)
就是喜欢在松弛操作里面边更新dis边更新record,成功的写错了下标
点击查看代码
if(dis[c]>dis[calc(tmpx,tmpy)]+(mmap[x1][y1]=='1'?1:0))
{
rec[calc(tmpx,tmpy)][calc(i,j)]=dis[calc(i,j)];//这一行是错误的!!!
dis[c]=dis[calc(tmpx,tmpy)]+(mmap[x1][y1]=='1'?1:0);
if(!vis[calc(x1,y1)])qx.push(x1),qy.push(y1),vis[calc(x1,y1)]=1;
}
\(Third\)
就是刚刚那个地方把赋值写成了大于
点击查看代码
if(dis[c]>dis[calc(tmpx,tmpy)]+(mmap[x1][y1]=='1'?1:0))
{
rec[calc(tmpx,tmpy)][calc(i,j)]=dis[calc(i,j)];//这一行是错误的!!!
dis[c]>dis[calc(tmpx,tmpy)]+(mmap[x1][y1]=='1'?1:0);//喜欢复制粘贴?看看这行吧小子
if(!vis[calc(x1,y1)])qx.push(x1),qy.push(y1),vis[calc(x1,y1)]=1;
}
最后含泪贴上AC
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n,m,t;int rec[1000][1000];int dis[1000];bool vis[1000];
int calc(int x,int y){return m*(x-1)+y;}
bool valid(int x,int y){return 1<=x&&x<=n&&1<=y&&y<=m;}
double odis(int x,int y,int i,int j){return 1.0*(x-i)*(x-i)+1.0*(y-j)*(y-j);}
char mmap[35][35];
int c1[]={-1,0,1,0},c2[]={0,-1,0,1};
void spfa(int x,int y)
{
queue<int>qx,qy;
memset(dis,0x3f,sizeof dis);
memset(vis,0,sizeof vis);
dis[calc(x,y)]=(mmap[x][y]=='1'?1:0);
qx.push(x),qy.push(y);vis[calc(x,y)]=1;
while(!qx.empty())
{
int tmpx=qx.front(),tmpy=qy.front();
for(int i=0;i<=3;i++)
{
int x1=tmpx+c1[i],y1=tmpy+c2[i];
if(!valid(x1,y1))continue;
int c=calc(x1,y1);
if(dis[c]>dis[calc(tmpx,tmpy)]+(mmap[x1][y1]=='1'?1:0))
{
dis[c]=dis[calc(tmpx,tmpy)]+(mmap[x1][y1]=='1'?1:0);
if(!vis[calc(x1,y1)])qx.push(x1),qy.push(y1),vis[calc(x1,y1)]=1;
}
}
qx.pop(),qy.pop(),vis[calc(tmpx,tmpy)]=0;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
rec[calc(x,y)][calc(i,j)]=dis[calc(i,j)];
}
int main()
{
scanf("%d%d%d",&n,&m,&t);
char k=getchar();
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)mmap[i][j]=getchar();
k=getchar();
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
spfa(i,j);
double ans1=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int x=1;x<=n;x++)
for(int y=1;y<=m;y++)
if(rec[calc(i,j)][calc(x,y)]<=t) ans1=max(ans1,odis(i,j,x,y));
// for(int i=1;i<=n;i++)
// for(int j=1;j<=m;j++)
// for(int k=1;k<=n;k++)
// for(int l=1;l<=m;l++)
// printf("dis:%d %d--->%d %d==%d\n",i,j,k,l,rec[calc(i,j)][calc(k,l)]);
printf("%.6lf",sqrt(ans1));
return 0;
}
本文来自博客园,作者:Hanggoash,转载请注明原文链接:https://www.cnblogs.com/Hanggoash/p/16736141.html