• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

llwwll

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

10.11

T1 理想的正方形

题面

分析

容易想到 \(a*b*n^2\) 的暴力
\(a*b\) 是必然的时间复杂度,考虑优化 \(n^2\) 的效率
可以\(a*b*n\) 遍历每个点后 \(n\) 个,维护最大最小值
查询时查询每个点往下 \(n\) 列的维护的最大最小值
因为 \(n\) 很小,所以 \(a*b*n\) 能过

点击查看代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 1000010
#define N 1010
#define int long long
using namespace std;
int a,b,n,G[N][N];
int max_x[N][N],min_x[N][N];
int Ans=2147483647,Ans_mx,Ans_mn;
template<typename T>void read(T &x)
{
	x=0;char c=getchar();T neg=0;
	while(!isdigit(c))neg|=!(c^'-'),c=getchar();
	while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
	if(neg)x=(~x)+1;
}
template<typename T>void wr(T x)
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)wr(x/10);
	putchar((x-x/10*10)^48);
	return ;
}
signed main()
{
//	freopen("square.in","r",stdin);
//	freopen("square.out","w",stdout);
	read(a);read(b);read(n);
	memset(min_x,127,sizeof min_x);
	for(int i=1;i<=a;i++)
	for(int j=1;j<=b;j++) read(G[i][j]);
	
	for(int i=1;i<=a;i++)
	{
		for(int j=1;j<=b-n+1;j++)
		{
			for(int k=0;k<n;k++) max_x[i][j]=max(max_x[i][j],G[i][j+k]),min_x[i][j]=min(min_x[i][j],G[i][j+k]);
		}
	}
	for(int i=1;i<=a-n+1;i++)
	{
//		cout<<endl;
		for(int j=1;j<=b-n+1;j++)
		{
			Ans_mn=2147483647;
			Ans_mx=0;
//			cout<<i<<" "<<j<<" "<<max_x[i][j]<<" "<<min_x[i][j]<<endl;
//			cout<<endl;
			for(int k=0;k<n;k++) 
			{
				
				Ans_mx=max(Ans_mx,max_x[i+k][j]);
				Ans_mn=min(Ans_mn,min_x[i+k][j]);
//				cout<<Ans_mx<<"-*-"<<Ans_mn<<" "<<Ans<<endl;
			}
			Ans=min(Ans,Ans_mx-Ans_mn);
		}
	}
	wr(Ans);
	return 0;
}
/*
5 4 2 
1 2 5 6 
0 17 16 0 
16 17 2 1 
2 10 2 1 
1 2 2 2
*/

T2 凸多边形的分割

image

分析

区间 \(dp\)
考场上没想出来,想到是图论,每个点建边,\(DFS\)搜索,但是 \(n\) 在 \(20\) 以上 \(TLE\)
正解是 区间\(DP\)
常规变化将环拓展为 \(2\) 倍数组
\(dp[l][r]\) 表示覆盖 \(l\) 到 \(r\) 的最小权值和
枚举 \(l\) 到 \(r\) 的中间点 \(k\)
要合并到 \(l~r\) 区间,所加上的权值就是新形成的三角形
例如枚举 \(l=1\quad r=6\quad k=3\) 时
如图
画个图应该很好理解
image
因此方程转移即为 \(dp[l][r]=dp[l][k]+dp[k][r]+val[l]+val[k]+val[r]\)
注意区间小于 \(2\) 时无法构成三角形,此时为 \(dp=0\)

点击查看代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 1000010
#define N 200100

using namespace std;
int n;
__int128 dp[200][200],val[200];
__int128 Ans=(__int128)(1e30);
template<typename T>void read(T &x)
{
	x=0;char c=getchar();T neg=0;
	while(!isdigit(c))neg|=!(c^'-'),c=getchar();
	while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
	if(neg)x=(~x)+1;
}
template<typename T>void wr(T x)
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)wr(x/10);
	putchar((x-x/10*10)^48);
	return ;
}
inline __int128 Min(__int128 a, __int128 b) { return a < b ? a : b; }
signed main()
{
//	freopen("abc10.in","r",stdin);
	read(n);
	for(int i=1;i<=n;i++) read(val[i]),val[i+n]=val[i];
	for(int i=1;i<=2*n;i++)
	{
		for(int j=1;j<=2*n;j++) dp[i][j]=(__int128)(1e30);
	}
	for(int i=1;i<=2*n;i++) dp[i][i+1]=0;
	for(int len=2;len<=n-1;len++)
	{
		for(int st=1;st<=n;st++)
		{
			for(int k=st+1;k<st+len;k++)
			{
				dp[st][st+len]=Min(dp[st][st+len],dp[st][k]+dp[k][st+len]+val[st]*val[st+len]*val[k]);
			}
		}
	}
	for(int i=1;i<=n;i++) Ans=Min(Ans,dp[i][i+n-1]);
	wr(Ans);
	return 0;
}

T3 电路维修

image
image

分析

最短路 \(BFS\)
容易想到,沿着可以走的路拓展
跑最短路即可
但本题有一个奇妙的性质
因为一直方向在右下
指向↘的电路都在 \(x+y=\) 偶数 的点上
指向↗的电路都在 \(x+y=\) 奇数 的点上
有了这个奇妙的性质就很好枚举可以到达的点了
↘可能到达的点
image
↗可能到达的点
image
然后用堆维护最短路

点击查看代码
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<algorithm>
#include<cstring>
#define maxn 1000010
#define N 1010
#define int long long
using namespace std;
struct node{
    int x,y,s;
    bool operator<(const node x)const{  return s>x.s;   }
}mi;
priority_queue< node > v;
int m,n,tx,ty,c;
char t;
bool G[618][618];
bool f[618][618];
int dx[2][6]={0,0,1,-1,1,-1,  0,0,1,-1,1,-1};
int dy[2][6]={1,-1,0,0,1,-1,  1,-1,0,0,-1,1};
signed main()
{
//	freopen("cir.in","r",stdin);
//	freopen("cir.out","w",stdout);
    scanf("%lld",&c);
    while(c--)
    {
        scanf("%lld%lld",&m,&n);
        for(int i=1;i<=m;i++)
            for(int j=1;j<=n;j++)
            {
                cin>>t;
                if(t=='/')
                    G[i][j]=1;
                else
                    G[i][j]=0;
            }
        if((m+n)%2)
        {
            cout<<"NO SOLUTION"<<endl;
            continue;
        }
        mi.x=1;
        mi.y=1;
        mi.s=G[1][1];
        v.push(mi);
        while(v.size())
        {
            node st=v.top();
            
            if(st.x==m&&st.y==n)
            {
            	printf("%lld\n",st.s);
                break;
            }
            for(int i=0;i<6;i++)
            {
                tx=st.x+dx[(st.x+st.y)%2][i];
                ty=st.y+dy[(st.x+st.y)%2][i];
                if(tx>0&&ty>0&&tx<=m&&ty<=n&&!f[tx][ty])
                {
                    f[tx][ty]=1;
                    mi.x=tx; mi.y=ty;
                    if((tx+ty)%2==G[tx][ty]) mi.s=st.s;
                    else mi.s=st.s+1;
                    v.push(mi);
                }
            }
            v.pop();
        }
        while(v.size())
        v.pop();
        memset(f,0,sizeof(f));
    }
    return 0;
}
/*
1
3 5 
\\/\\
\\///
/\\\\
*/

T4 换教室

没有什么比小花讲的更好了

image
image

点击查看代码
#include<bits/stdc++.h>
#define maxn 2010
#define int long long
using namespace std;
int n,m,v,e;
int c[maxn],d[maxn];
double p[maxn];
double dp[maxn][maxn][2],f[maxn][maxn];
int u,r;
double val;
inline double min(double a,double b){
    return a<b?a:b;
}
inline int  read(){
    int  k = 0;
    char c;
    c = getchar();
    while(!isdigit(c))c = getchar();
 	while(isdigit(c)){
        k = (k<<1)+(k<<3)+c-48;
    	c = getchar();
    }
    return k ;
}
signed main()
{
//	freopen("classroom4.in","r",stdin);
	scanf("%lld%lld%lld%lld",&n,&m,&v,&e);// num  limit  tot  edge// 注意#define int long long 
	for(int i=1;i<=n;i++) c[i]=read();
	for(int i=1;i<=n;i++) d[i]=read();
	for(int i=1;i<=n;i++) cin>>p[i];
	
	memset(f,0x7f,sizeof f);// double 可以使用 memset 
	
	for(int i=1;i<=e;i++) 
	{
		u=read(); r=read();val=read();
		f[u][r]=f[r][u]=min(f[u][r],val);
	}
	
	for(int k=1;k<=v;k++)// Floyd 的 k 放在外层 
	for(int i=1;i<=v;i++)
		for(int j=i+1;j<=v;j++)
			
				f[i][j]=f[j][i]=min(f[i][j],f[i][k]+f[k][j]);
				
	for(int i=1;i<=v;i++) f[i][i]=0;// 注意 自己到自己 距离为 0  (感谢tyj 
			
	memset(dp,0x7f,sizeof dp);// double 可以使用 memset 
	
	dp[1][0][0]=dp[1][1][1]=0;
	
	
	for(int i=2;i<=n;i++){// 大好的 DP  
     double add1=f[c[i-1]][c[i]];
      for(int j=0;j<=min(m,i);j++)
       {                     
          dp[i][j][0]=min(dp[i-1][j][0]+add1,dp[i-1][j][1]+f[d[i-1]][c[i]]*p[i-1]+f[c[i-1]][c[i]]*(1-p[i-1]));
          if(j!=0)
          dp[i][j][1]=min(dp[i-1][j-1][0]+f[c[i-1]][d[i]]*p[i]+f[c[i-1]][c[i]]*(1-p[i]),dp[i-1][j-1][1]+f[c[i-1]][c[i]]*(1-p[i-1])*(1-p[i])+f[c[i-1]][d[i]]*(1-p[i-1])*p[i]+f[d[i-1]][c[i]]*(1-p[i])*p[i-1]+f[d[i-1]][d[i]]*p[i-1]*p[i]);
       }   
    }          
	
	double hahaha=9999999999;
    for(int i=0;i<=m;i++) 
	{
		hahaha=min(dp[n][i][0],min(dp[n][i][1],hahaha));
	}
    
    printf("%.2lf",hahaha);
}
/*
3 2 3 3
2 1 2
1 2 1
0.8 0.2 0.5 
1 2 5
1 3 3
2 3 1

*/

posted on 2022-10-11 20:28  llwwll  阅读(59)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3