生日快乐
这题看起来蛋糕可以乱切,但实际上不行,设当前矩形为长 x x x,宽 y y y,分 k k k 块,显然分出一块蛋糕长最短为 x / k x/k x/k,宽最短为 y / k y/k y/k,而且切出来的蛋糕,一定是最短长宽的倍数,不然后面的蛋糕一定不能切出来面积一样。这样直接深搜就行了。
#include<bits/stdc++.h>
#define FRE freopen("happy.in","r",stdin);\
freopen("happy.out","w",stdout);
using namespace std;
template<typename T>inline void read(T &x){
T ch=getchar();x=0;
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
}
double dfs(int k,double x,double y){
if(k==1){return max(x/y,y/x);}
double lx=x/k,ly=y/k,ans=99999999.9,r1,r2;
for(int i=1;i<=k/2;++i){
r1=max(dfs(i,lx*i,y),dfs(k-i,x-lx*i,y));
r2=max(dfs(i,x,ly*i),dfs(k-i,x,y-ly*i));
ans=min(ans,min(r1,r2));
}
return ans;
}
int main() {
int x,y,n;
read(x),read(y),read(n);
printf("%.6lf",dfs(n,x,y));
return 0;
}
最长距离
最短路转化, d i s t dist dist 数组存的是从源点到当前点最少需要搬多少石头,对所有 d i s t dist dist 小于 t t t 的数组更新答案就行了。
#include<bits/stdc++.h>
using namespace std;
int n,m,t,ans;
int dx[]={1,0,-1,0},
dy[]={0,-1,0,1};
int dist[40][40];
bool f[40][40];
bool v[40][40];
queue<int>qx;
queue<int>qy;
void spfa(int x,int y)
{
memset(dist,0x3f,sizeof dist);
memset(v,0,sizeof v);
dist[x][y]=f[x][y];v[x][y]=1;
qx.push(x),qy.push(y);
while(qx.size()){
int l=qx.front(),r=qy.front();
qx.pop(),qy.pop();
v[l][r]=0;
for(int i=0;i<4;++i){
int tx=l+dx[i],ty=r+dy[i];
if(tx<1||ty<1||tx>n||ty>m) continue;
int tz=0;if(f[tx][ty]) tz=1;
if(dist[tx][ty]>dist[l][r]+tz){
dist[tx][ty]=dist[l][r]+tz;
if(!v[tx][ty]) qx.push(tx),qy.push(ty),v[tx][ty]=1;
}
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(dist[i][j]<=t)
ans=max(ans,(i-x)*(i-x)+(j-y)*(j-y));
}
int main()
{
scanf("%d%d%d",&n,&m,&t);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%1d",&f[i][j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
spfa(i,j);
printf("%.6f",sqrt(1.0*ans));
return 0;
}
Windy 数
- 数位
D
P
DP
DP
设 F [ i , j ] F[i,j] F[i,j] 表示前 i i i 位开头为 j j j 的数有多少个。易得转移方程 F [ i + 1 ] [ j ] = ∑ F [ i , k ] ( ∣ j − k ∣ ≥ 2 ) F[i+1][j]=\sum F[i,k](\left\vert j-k \right\vert \geq 2) F[i+1][j]=∑F[i,k](∣j−k∣≥2)这个解决了,现在要求求 x x x 以内的 W i n d y Windy Windy 数有多少个。假设 x = 54201 x=54201 x=54201,首 先对于第一位 5 5 5 来说 19999 19999 19999 到 49999 49999 49999 以内的 W i n d y Windy Windy 数都要算入,然后对于下一位 4 4 4 来说 50999 50999 50999 到 53999 53999 53999 内满足条件的数都要算入,后面几位同理。但此时发现到后面几位时因为开头为 54 54 54 所以后面的无论怎样都满足不了,就不用考虑了若到最后都没有出现 54 54 54 这样类似的情况,例如 53130 53130 53130,说明这个数本身也是 W i n d y Windy Windy 数,要记入答案。完了吗?没有!以上讨论都是建立在为位数位 5 5 5 的情况, 9999 9999 9999 及以下的都没有考虑进去,这也要统计。
#include<bits/stdc++.h>
using namespace std;
int a,b,ans;
int f[11][11];
void pre(){
for(int i=0;i<10;++i) f[1][i]=1;
for(int i=1;i<=9;++i)
for(int j=0;j<10;++j)
for(int k=0;k<10;++k)
if(abs(j-k)>=2) f[i+1][j]+=f[i][k];
}
int get(int a){
int A[11];
int ans=0,la=0;
while(a){
A[++la]=a%10;
a/=10;
}
for(int j=1;j<A[la];j++) ans+=f[la][j];
for(int i=la-1;i>=1;i--){
for(int j=0;j<A[i];j++)
if(abs(A[i+1]-j)>1)
ans+=f[i][j];
if(abs(A[i+1]-A[i])<2) break;
if(i==1) ans++;
}
for(int i=1;i<la;i++)
for(int j=1;j<=9;j++)
ans+=f[i][j];
return ans;
}
int main() {
pre();
read(a),read(b);
if(b<10) prt(b-a+1);
else prt(get(b)-get(a-1));
return 0;
}
- 打表
一开始做这题的时候,我本以为 2 e 9 2e9 2e9 内的 W i n d y Windy Windy 数很少,就想着跑一遍来着,但是发现挺多的,
老实写完数位动态规划后却发现一千万以内的跑得很快,于是换了种打表方式,暴力找出每个一千万内有多少个 W i n d y Windy Windy 数,开个 200 200 200 的数组来存,对于输入的 a , b a,b a,b 若所属的一千万相同或挨在一起,就暴力跑出 a a a 到 b b b 间有多少,否则先加上他们之间所有的一千万内的 W i n d y Windy Windy 数,再暴力跑。
#include<bits/stdc++.h>
using namespace std;
int p[201]={/*表当然自己就能打了*/};
bool check(int x){
int a=x%10,b;
x/=10;
while(x){
b=x%10;
x/=10;
if(abs(a-b)<2) return 0;
a=b;
}
return 1;
}
int a,b,ans;
int main() {
read(a),read(b);
if(b<10){cout<<(b-a+1);}
int x=a/10000000+1,y=b/10000000-1;
if(x>y){
for(int i=a;i<=b;++i)
if(check(i)) ans++;
}
else{
for(int i=x;i<=y;++i)
ans+=p[i];
for(int i=a;i<x*10000000;++i) if(check(i)) ans++;
for(int i=(y+1)*10000000;i<=b;++i) if(check(i)) ans++;
}
prt(ans);
return 0;
}
/*
546561 56465156
*/