poj一周刷题记录

来源:互联网 发布:淘宝hd怎么安装旧版本 编辑:程序博客网 时间:2024/06/05 19:36

第一周
3907
题意:已知n个顶点坐标,求多边形面积
解法:顺时针求依次求相邻两点坐标叉积相加除二即为结果

3908
题意:对图中的点进行共两种操作
1.c(i,j):将i和j点连起来
2.d(i):删除点i,但是不影响其他点通过它构成的连通性
一种询问
3.q(i,j):询问i和j是否连通
解法:并查集。注意当点删除后,不能改变该点的父节点,因为可能在询问其他节点时,通过该节点,因此需要为该节点建立新点,因此加一个id数组表示表示当前点的位置

3921
题意:有向图至少删除多少点使得1到n的路径长度大于k。
解法:只需要删除在原图中从1到n不大于k的路径上的点。因此在新图中只需要保留这样的点即可。联想到拆点法可以将删点问题转化为删边问题。建图如下。
1.将点拆成i和i+n。增加原图中的边add(i+n,j,INF)
2.增加原图中1到n不大于k路径上的点边add(i,i+n,1)
这样一来最小割只会删除点权为1的边,即相当于删点。删点后图中不存在1到n长度不大于k的路径。
拓展:对偶命题:删除尽量多的点使得1-n路径长小于k
解法:求1-n最短路径,保留最短路径上的点,其他点全部删除即可
条件改为s1->t2的最短路径小于k1,s2->t2的最短路径小于k2,最多删除点数。
1)预处理最短路
2)O(n^2)枚举相交路径即可

3925
题意:求n个点中的m个点的最优比例生成树(n<=15)
解法:二进制枚举n位中m位为1的所有数字

        for(int s=(1<<m)-1,u=1<<n;s<u;){            cnt=0;            for(int j=0;(1<<j)<=s;j++){                if((1<<j)&s){                    tmp[cnt++]=j;                }            }            mintree(tmp,cnt);            int b=s&(-s);            s=(s+b)|(((s^(s+b))>>2)/b);        }

对于每m个点,建图,求最小生成树,然后除以点权和即可。最后答案取最小。

3927
题意:已知n段闭区间[Si,Ti],每段区间必须选择严格大于区间长度一半的连续区间,问是否存在一种选择方案,使得区间没有重叠(顶点重合不算做重叠)
解法:贪心。按区间中点进行排序,因为题意区间必须经过区间中点,因此中点小的一定先访问。

3928
题意:n个数中求3个连续上升的序列个数(不一定连续)
解法:树状数组

1856
题意:一个矩阵中包含”#”和”.”两种字符,判断该矩阵”#”是否组成若干不相交(甚至角落也不相交)的小矩形。
解法:对每个点进行dfs。关键在于判断方法:记录最大和最小的x与y坐标和遍历的#个数cnt,如果cnt==(maxx-minx+1)*(maxy-miny+1),则是小矩形,否则不是。

2734
题意:判断棋盘中未被攻击到的位置
解法:将所有棋子可以攻击到的位置全部遍历并记录下来即可

2922
题意:求从矩阵左上角走到右下角(可以向四方向行走)的最小落差路径。
解法:最小最大值,可以二分求解。二分落差大小,然后进行dfs查找可行路径。如此一来会TLE。由于题中的海拔最大值不过200,可以在落差基础上枚举取值区间[l,r]。这样可以在O(n)复杂度内求出是否存在[l,r]区间路径。
拓展:可以求任意有向图的最小落差路径,复杂度O(log(maxl)*maxl*n)
maxl是点的最大权值。

2264
题意:求两序列最长公共字序列并输出最短拼接序列
解法:记录最长公共子序列的相应下标,并一次输出各个字符即可

2893
题意:一个n*m的矩阵由0-n*m-1的数字填充而成。现在用0和上下左右四个位置的数字进行交换,是否可以将当前矩阵经过有限次交换变成1,2…m*n-1,0的矩阵,0为右下角的元素。
解法:应该有如下结论:列为奇数时,逆序数奇偶性相同的矩阵之间可以相互转化;列为偶数时,和0所在行数以及初始逆序数奇偶性相关。因此只需要统计初始奇偶性和0所在行数即可。

读入加速

ll read(){    ll x=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}

3373
题意:100长度数字至少经过多少个数字改变能够使得该数字被1e4内的数字k整除,在所有结果数字中取最小的那个。
解法:记忆化搜索。先枚举更改次数i;在次数限制下,记录前j个数字模k的余数mod,枚举当前数字改为何数,递归下去。dp值记录前j个数字模k余mod时在dp[j][mod] 次数内无法得到最终目标。

#include<iostream>#include<cstring>#include<cstdio>#include<vector>using namespace std;const int maxn = 100+5;const int maxk = 10000+5;int k;char ch[maxn];int tmp[maxn];int dp[maxn][maxk];//dp[i][j]:已知[1,i-1]区间数模k余j,[i,l-1]区间数在dp[i][j]次改变内无法将[0,l-1]区间数变成模k余0的数字vector<int> ans;int l;bool dfs(int n,int change,int mod){//当前[0,n-1]区间数模k余mod,问[n,l-1]是否能在change次改变内使得[0,l-1]区间数模k余0    if(n==l){        if(mod==0) return true;        return false;    }    if(dp[n][mod]!=-1&&dp[n][mod]>=change) return false;    for(int i=0;i<=9;i++){        if(n==0&&i==0) continue;//不含前导零        if(tmp[n]==i) { if(dfs(n+1,change,(mod*10+i)%k)) { ans.push_back(i); return true; } }        else if(change>0) { if(dfs(n+1,change-1,(mod*10+i)%k)) { ans.push_back(i); return true; } }    }    dp[n][mod]=change;    return false;}int main(){    while(scanf("%s%d",ch,&k)!=EOF){        l=strlen(ch);        for(int i=0;i<l;i++) tmp[i]=ch[i]-'0';        ans.clear();        memset(dp,-1,sizeof(dp));        for(int i=0;i<l;i++){            if(dfs(0,i,0)){                break;            }        }        for(int i=ans.size()-1;i>=0;i--) printf("%d",ans[i]);        printf("\n");    }}

2508
题意:求圆锥上两点间距离
解法:展开圆锥,用余弦定理解决。注意补角情况

2681
题意:求覆盖平面内m个点的最小矩形面积
解法:x轴方向枚举区间两端点,y方向在所有点上用尺取法。
使用尺取法的条件:尾节点下标增加,目标值增加;头节点反之。

2564
题意:给定n个由a-z组成的字符串,按字典序从小到大排列,如果可以通过增加/减少/改变一个字符得到另一个字符串,则这两个字符串有关系,求最长关系链,链中相邻两个字符串均有关系。
解法:查找i之前与i有关系的字符串+dp求最长路。
第一步可用三种方法。
先将i字符串增加/减少/改变一个字符得到新字符串j,然后:
一:二分查找[0,i-1]区间内字符串是否含j
二:hash查找,需要提前插入
三:trie树查找,需要提前插入

3012
题意:得到公式发现是二项式展开式
解法:合并用快速幂求解即可

1932
题意:有向有环图,问是否存在从s到t的的路径,满足s到达该路径上任意一点时路径长度都大于0。到达一个顶点两次顶点值算两次。
解法:化用spfa,在判断条件上,将最短路改成最长路,且必须终点能到达t。正环特判,一定存在。

2065
题意:模线性方程组
解法:高斯消元

2137
题意:在n组点中各取一点,依次连接,形成一个环状。求环状的最小周长。
解法:dp。dp[i][j][k]:从第1个选择的j点到第i个选择的k点的最短路径长度
ans=min(ans,dp[n][j][k]+dis(1,j,n,k));

2355
题意:n个车站依次坐落在x轴上,相邻两个车站间的距离不超过L3。两站之间的车费是分段函数:
[0,l1] => c1
[0,l2] => c2
[0,l3] => c3
求从st车站到en车站的最少花费
解法:常规dp,dp[i]=min(dp[j]+cost(i,j))
优化一:二分法,找到与i车站最远的c1,c2,c3花费车站。O(n*logn)
优化二:尺取法,取p1,p2,p3为三个当前最优c1,c2,c3花费车站。O(n)

2722
题意:第一象限内有一个角度和n个正方形,将矩形塞入角度中,使得围成封闭区域,求封闭区域的最大面积
解法:正方形排列成对角线时面积最大。直接推倒公式求解即可

3377
题意:特殊的矩形图求最短路
解法一:dijkstra堆优化。
解法二:由于每点的度数有限,并且存在某种顺序,所以可以通过dp来解决。

3171
题意:使用每个区间都有相应代价,求这些区间覆盖整个区间的最小代价和
解法:dp。
首先将区间进行排序,按起始和终点排序均可,对应不同优化方法。
dp[i]:以第i个区间结尾的最小代价和。dp[i]=min(dp[j],ed[j]>=st[i]-1)+cost[i]
法一:按起点排序。st[i]随i增加,因此可以使用队列进行优化(出列后不会使用到该值)。将元素仿如优先队列中,以dp值从小到大排列,每次察看队头元素的ed是否>=st[i]-1,不满足,则出列,以后都不会用到该值。
满足,队头dp值即为最优值。
法二:按起点/终点排序。以ed为下标dp为值建立线段树,每次询问下标大于等于st[i]-1的最小dp值

3093
题意:n个数中挑选若干数,使其和不大于d,如果再任意挑选一个数后,和大于d,求这样选择数字的方案数。
解法一:将数字从小到大排序。dp[i][j]:前i个数中d为j时满足题意的方案数。
dp[i][j]=dp[i-1][j](当sum[i]>j时)+dp[i][j-a[i]](当j>=a[i]时)
初始化dp[0][j]=1,0<=j<=d
解法二:枚举最小的未选数字k,对k+1-n进行0-1背包处理

3612
题意:将n个数字中的若干个变大,变大代价为(x-a[i])*(x-a[i]),x为变化后的数字,a[i]为原来的数字。变化后相邻两数差的绝对值之和与常数c的乘积为第二部份代价,求代价最小值。
解法:dp[i][j]为第i个数字变成j时前i个数字的最小代价
dp[i][j]=min{ dp[i-1][k]+c*|j-k|+(j-a[i])*(j-a[i]),j>=a[i] }
当k >j时,dp[i][j]=min{dp[i-1][k]+c*k}-c*j+(j-a[i])*(j-a[i])
当k< j时,dp[i][j]=min{dp[i-1][k]-c*k}+c*j+(j-a[i])*(j-a[i])
大括号内的值仅与k有关而与j无关,大括号外的相反,因此可以提前维护
A[j]=min{dp[i-1][k]+c*k,k>j}
B[j]=min{dp[i-1][k]-c*k,k< j}

3600
题意:两个由0和1组成的二维序列A和B,问B是否可以通过删除若干行与列使得A和B相同,row,col<=20
解法:枚举+尺取法。先枚举B中保留的列,在行上进行尺取,如果可以的话尽量选取较靠上面的行,因此可以尺取。
复杂度:1e5*20=1e6

1385
题意:求多边形重心(包括凹多边形)
解法:将n边形分成n-2个三角形,分别求出重心并赋予面积为权值,求新重心

2795
题意:给定一个先序遍历序列,求对应不同树的个数
解法: O(n^3)DP
if(a[x]==a[i]&&a[x]==a[j])
dp[i][j]=(dp[i][j]+(dp[i][x]*dp[x+1][j-1])%mod+dp[i+1][j-1])%mod;

0 0