题解:
一开始想错了,误以为只要找到等候时间最长的那一层,再加上楼层数,就是结果了,但实际上
还是太年轻。AC思路是,暴力搜每层,用数组记录每层所需的最大时间,再取最大数为结果;那么如何记
录每层所需的最大时间?
每层所需的最大时间是:max(s-a[i].f,a[i].t)+a[i].f,即电梯从该楼层下到地面所需的时间与
该楼层的等待时间的较大者,加上该楼层数,即结果。
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct passenger
{
int f,t;
} a[105];
int main()
{
int n,s,maxt=0;
scanf("%d%d",&n,&s);
for(int i=0;i<n;i++)
{
scanf("%d%d",&a[i].f,&a[i].t);
maxt=max(maxt,max(s-a[i].f,a[i].t)+a[i].f);
}
printf("%d\n",maxt);
return 0;
}
--------------------------------------------------------------------------------------------------------------------
题解:
超时:试图顺序读串b中长度为lena的子串,再遍历子串和串a,看是否相同,不同则sum++,但结
果就是超时了,因为串a最长可以到200000;
AC思路:用一个long long型的二维数组c,且第二维大小为2,遍历串b,c[][0]保存串b中0的个数,
c[][1]保存串b中1的个数;最后再遍历串a,如果ai=‘1’,那么ans+=c[lenb-lena+i][0]-c[i][0]+(a[i]==b[i])?0:1;
否则,ans+=c[lenb-lena+i][1]-c[i][1]+(a[i]==b[i])?0:1 。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char a[200005],b[200005];
long long c[200005][2];
int main()
{
scanf("%s%s",a,b);
long long ans=0;
int lena=strlen(a),lenb=strlen(b);
for(int i=0;i<lenb;i++)
{
if(i>0)
{
c[i][0]=c[i-1][0];
c[i][1]=c[i-1][1];
}
c[i][b[i]-'0']++;
}
for(int i=0;i<lena;i++)
{
if(a[i]=='1')
ans+=(c[lenb-lena+i][0]-c[i][0]+(a[i]==b[i]?0:1));
else
ans+=(c[lenb-lena+i][1]-c[i][1]+(a[i]==b[i]?0:1));
}
printf("%I64d\n",ans);
return 0;
}
------------------------------------------------------------------------------------------------------------------
题解:
有n个灯塔从左往右排列成一行,第i个灯塔对应位置ai、能量bi;
第i个灯塔被激活,它就会毁掉左边bi距离内的所有灯塔(不会毁自己),且激活是从右往左每次激活一个;
然后可以增加一个灯塔在最右边,可以是任意的位置ai(只要在最右就好)和能量bi,让被毁的灯塔数最少;
用数组a[]保存位置pos的能量,数组dp[]保存假设位置pos的灯塔被激活所剩下的灯塔数目,nmax记录最远位置,res记录最大的剩余灯塔数,
//记得数组a和数组dp都要先清零;
关于dp的状态转移:如果有灯塔在第一个位置,那么记录dp[0]为1,即灯塔本身,然后从1到nmax遍历,
如果位置i灯塔的能量a[i]大于等于它所在位置,说明它左边所有的灯塔都会被毁,只剩下自己,即dp[i]=1;
而若小于,那么从位置i-a[i]-1到位置i之间的灯塔都会被毁,那么只剩下位置i-a[i]-1的剩余灯塔数+1(+1是位置i灯塔),即dp[i]=dp[i-a[i]-1]+1。
最后,最小的毁灭数则是n-res。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define MAXN 1000000
int a[MAXN+5],dp[MAXN+5];
int main()
{
int n,pos,nmax=0,res=0;
scanf("%d",&n);
memset(a,0,sizeof(a));
memset(dp,0,sizeof(dp));
for(int i=0;i<n;i++)
{
scanf("%d",&pos);
scanf("%d",&a[pos]);
nmax=max(nmax,pos);
}
if(a[0]>0) dp[0]=1;
res=max(res,dp[0]);
for(int i=1;i<=nmax;i++)
{
if(a[i]==0)
dp[i]=dp[i-1];
else
{
if(a[i]>=i)
dp[i]=1;
else
dp[i]=dp[i-a[i]-1]+1;
}
res=max(res,dp[i]);
}
printf("%d\n",n-res);
return 0;
}
---------------------------------------------------------------------------------------------------------------
题解:
从高往低滑,且只能向上下左右四个相邻点滑去,求最大滑行长度。
二维数组a[][]保存各点高度,二维数组m[][]保存以点[i][j]为起点往下滑行的最大长度(开始要将所有数组元素置为-1),再用递归函数dp返回所有点中的最大长度;
之所以要用数组m保存数据,是防止超时,保存好了,以便下一次递归时直接返值,而不是又要进行计算。
递归函数dp(int i,int j):注意进行判断和return还有递归的顺序,先判断该点求过值没,如果有求过,就返回该点的值(防TLE);不然的话,就开始对该点的上下左右四个方向进行对比(还要判断该方向上有没有点、以及该点的高度是否小于原点高度),取最大值;最后才写如果该点==-1(即还没求过值),则该点对应的长度m[i][j]为1的判断语句,在该判断语句外最后写return 点i,j对应的最大长度。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int a[105][105],m[105][105];
int r,c;
int dp(int i,int j)
{
if(m[i][j]!=-1) return m[i][j];
if(i-1>=0&&a[i-1][j]<a[i][j]) m[i][j]=max(m[i][j],dp(i-1,j)+1);
if(i+1<r&&a[i+1][j]<a[i][j]) m[i][j]=max(m[i][j],dp(i+1,j)+1);
if(j-1>=0&&a[i][j-1]<a[i][j]) m[i][j]=max(m[i][j],dp(i,j-1)+1);
if(j+1<c&&a[i][j+1]<a[i][j]) m[i][j]=max(m[i][j],dp(i,j+1)+1);
if(m[i][j]==-1) m[i][j]=1;
return m[i][j];
}
int main()
{
int maxlen=0;
scanf("%d%d",&r,&c);
memset(m,-1,sizeof(m));
for(int i=0;i<r;i++)
for(int j=0;j<c;j++)
scanf("%d",&a[i][j]);
for(int i=0;i<r;i++)
for(int j=0;j<c;j++)
maxlen=max(maxlen,dp(i,j));
printf("%d\n",maxlen);
return 0;
}
-----------------------------------------------------------------------------------------------------------------
题解:
输出最长公共子序列的长度。
状态转移方程:
maxlen[i][j]=maxlen[i-1][j];
if(s1[i]>s2[j]&&nmax<maxlen[i-1][j])
nmax=maxlen[i-1][j];
if(s1[i]==s2[j])
maxlen[i][j]=nmax+1;
maxlen[i][j]二维数组(先清零)保存 到串1第i和串2第j个元素为止 的lcis长度,nmax记录当前的最大lcis长度,
先拿串1的第1个元素 与 串2 的元素依次比较,若串1的第1个元素>串2的第j个元素【保证了是上升序列】,且nmax小于maxlen[0][j]记录的lcis长度【用来得到该阶段的最大长度】,那么更新nmax为maxlen[0][j]所记录的长度;若串1第1个元素==串2第j个元素,那么长度+1,即maxlen[1][j]=nmax+1;
如果上述条件都不满足的话,那么maxlen[1][j]的值等于maxlen[0][j]的值,即保留之前所记录的长度;依此类推。
最后maxlen[len1][j] (j from 1 to len2)则保存了len2个长度值,再比较得出最大值即可。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 500
int n,len1,len2,nmax;
int s1[MAXN+5],s2[MAXN+5];
int maxlen[MAXN+5][MAXN+5];
int main()
{
scanf("%d",&n);
while(n--)
{
scanf("%d",&len1);
for(int i=1;i<=len1;i++)
scanf("%d",&s1[i]);
scanf("%d",&len2);
for(int i=1;i<=len2;i++)
scanf("%d",&s2[i]);
memset(maxlen,0,sizeof(maxlen));
for(int i=1;i<=len1;i++)
{
nmax=0;
for(int j=1;j<=len2;j++)
{
maxlen[i][j]=maxlen[i-1][j];
if(s1[i]>s2[j]&&nmax<maxlen[i-1][j])
nmax=maxlen[i-1][j];
if(s1[i]==s2[j])
maxlen[i][j]=nmax+1;
}
}
nmax=0;
for(int j=1;j<=len2;j++)
nmax=max(nmax,maxlen[len1][j]);
if(n>=1)
printf("%d\n\n",nmax);
else
printf("%d\n",nmax);
}
return 0;
}
---------------------------------------------------------------------------------------------------------------
题解:
非常之简单的模拟,看懂题就可以了。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int main()
{
int m1,m2;
int r1,r2,r3;
char s[205];
while(scanf("%d%d",&m1,&m2)!=EOF)
{
r1=r2=r3=0;
scanf("%s",s);
int len=strlen(s);
for(int i=0;i<len;i++)
{
if(s[i]=='A')
r1=m1;
else if(s[i]=='B')
r2=m2;
else if(s[i]=='C')
m1=r3;
else if(s[i]=='D')
m2=r3;
else if(s[i]=='E')
r3=r1+r2;
else if(s[i]=='F')
r3=r1-r2;
}
printf("%d,%d\n",m1,m2);
}
return 0;
}
----------------------------------------------------------------------------------------------------------------
题解:
找规律推公式;
要求组成的数列中,先有一递增或递减序列然后紧接一递增或递减序列,那么我们把最大的数,或是最小的数放
中间,把剩下的数放两边,每个数有两种选择,故2^(n-1),可以选最大数在中间,也可以选最小数在中间,所以是2^n,
又因为整个数列递增和递减分别多算了一次,故总共有2^n-2种,再mod p;
由于1<=n<=10^18,所以结果会很大,爆long long,一开始WA了,因为只用了快速幂,即使用了快速幂也会爆
long long ,所以用快速乘+快速幂来得到ans=2^n,最后结果res=(ans-2+p)%p;//因为res-2有可能得到负数,所以加上p。
快速乘实际上和快速幂原理相同,
<快速乘模板>:
ll multi(ll a,ll b,ll m)
{
ll ans=0;
while(b)
{
if(b&1) (ans+=a) %= m;
(a=a*2) %= m;
b/=2;
}
return ans;
}
<快速幂模板>:
ll pow_mod(ll a,ll b,ll m)
{
ll res=1;
while(b)
{
if(b&1) res=multi(res,a,m);
a=multi(a,a,m);
b/=2;
}
return res;
}
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
ll multi(ll a,ll b,ll m)
{
ll ans=0;
while(b)
{
if(b&1) (ans+=a) %= m;
(a=a*2) %= m;
b/=2;
}
return ans;
}
ll pow_mod(ll a,ll b,ll m)
{
ll res=1;
while(b)
{
if(b&1) res=multi(res,a,m);
a=multi(a,a,m);
b/=2;
}
return res;
}
int main()
{
ll n,p,ans;
while(scanf("%I64d%I64d",&n,&p)!=EOF)
{
if(n==1)
ans=1%p;
else
{
ans=pow_mod(2,n,p);
ans=(ans-2+p)%p;
}
printf("%I64d\n",ans);
}
return 0;
}
----------------------------------------------------------------------------------------------------------------
题解:
矩阵快速幂;
怎么个矩阵法呢,就是由已知fn=fn-1+fn+1推到:fn-1=fn-2+fn,得到fn=fn-2-fn-1,
于是构造矩阵: (fn-1,fn-2)*[1 -1]=(fn,fn-1),得到递推关系,
[1 0]
先特判n=1和n=2时的结果,剩下的利用矩阵和递推关系进行快速幂即可。
<矩阵快速幂模板>:
node mult(node a,node b) //进行矩阵的计算
{
node t;
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
{
t.m[i][j]=0;
for(int p=0;p<2;p++)
t.m[i][j]=((t.m[i][j]+a.m[i][p]*b.m[p][j])%MOD+MOD)%MOD;
}
return t;
}
void pow_mod(long long n)
{
original.m[0][0]=1,original.m[0][1]=-1;
original.m[1][0]=1,original.m[1][1]=0;
ans.m[0][0]=ans.m[1][1]=1;
ans.m[0][1]=ans.m[1][0]=0; //将ans初始化成2阶矩阵E
while(n)
{
if(n%2==1)
ans=mult(ans,original);
original=mult(original,original);
n/=2;
}
}
#include<iostream>
#include<cstdio>
using namespace std;
#define MOD 1000000007
struct node
{
long long m[2][2];
}original,ans;
node mult(node a,node b)
{
node t;
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
{
t.m[i][j]=0;
for(int p=0;p<2;p++)
t.m[i][j]=((t.m[i][j]+a.m[i][p]*b.m[p][j])%MOD+MOD)%MOD;
}
return t;
}
void pow_mod(long long n)
{
original.m[0][0]=1,original.m[0][1]=-1;
original.m[1][0]=1,original.m[1][1]=0;
ans.m[0][0]=ans.m[1][1]=1;
ans.m[0][1]=ans.m[1][0]=0;
while(n)
{
if(n%2==1)
ans=mult(ans,original);
original=mult(original,original);
n/=2;
}
}
int main()
{
long long x,y,n,res;
scanf("%I64d%I64d%I64d",&x,&y,&n);
if(n==1) res=(x%MOD+MOD)%MOD;
else if(n==2) res=(y%MOD+MOD)%MOD;
else
{
pow_mod(n-2);
res=((ans.m[0][0]*y+ans.m[0][1]*x)%MOD+MOD)%MOD;
}
printf("%I64d\n",res);
return 0;
}
---------------------------------------------------------------------------------------------------------------
题解:
遍历i从0到n-1,det(ai,ai+1)除以二,再求和即得到多边形面积。
<det模板>:
double det(point a,point b)
{
return a.x*b.y-b.x*a.y;
}
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
struct point
{
int x,y;
}a[105];
double det(point a,point b)
{
return a.x*b.y-b.x*a.y;
}
int main()
{
int n;
double area;
while(scanf("%d",&n)!=EOF)
{
area=0;
if(n==0)
break;
for(int i=0;i<n;i++)
scanf("%d%d",&a[i].x,&a[i].y);
a[n]=a[0];
for(int i=0;i<n;i++)
area+=det(a[i],a[i+1])/2.;
printf("%.1f\n",area);
}
return 0;
}
----------------------------------------------------------------------------------------------------------------
题解:
1.题所给坐标围成的多边形是否为凸包?
怎样才说明是凸包? ——只要任意连续三个点的叉乘(b-a,c-b)的正负相同,则说明方向相同,
只要有出现正负不同的,那么就不是凸包了;
s=(x1-x3)*(y2-y3)-(x2-x3)*(y1-y3)
当s>0时,p1,p2,p3三个点呈逆时针
当s<0时,p1,p2,p3三个点呈顺时针
当s=0时,p1,p2,p3三个点在一条直线上 */
2.判断出是凸包之后,钉子的圆心要在凸包中:
同样用叉乘,原理同上,(b-a,r-a)的正负与判断是否为凸包时的叉乘正负相同时,说明圆心在凸包中;
3.钉子的半径要大于凸包各边到圆心的距离:
叉乘(b-a,r-a)实际上就是边<a,r><a,b>形成的平行四边形的面积,所以用叉乘除以边<a,b>的长度,
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
const double eps=1e-8;
double r;
struct point
{
double x,y;
}a[10005],peg;
point sub(point a,point b)
{
a.x-=b.x;
a.y-=b.y;
return a;
}
int mul(point a,point b)
{
if(a.x*b.y-a.y*b.x>=0)
return 1;
else
return -1;
}
double dis(point a,point b)
{
if(fabs(a.x-b.x)<eps)
return fabs(peg.x-a.x) ;
else if(fabs(a.y-b.y)<eps)
return fabs(peg.y-a.y) ;
else
{
point c,d;
c=sub(a,b),d=sub(peg,b);
return fabs(c.x*d.y-d.x*c.y)/sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
}
int main()
{
int n,i,flag;
while(scanf("%d",&n)&&n>=3)
{
scanf("%lf %lf %lf",&r,&peg.x,&peg.y);
for(int j=0;j<n;j++)
scanf("%lf %lf",&a[j].x,&a[j].y);
a[n]=a[0];
flag=mul(sub(a[1],a[0]),sub(a[2],a[1]));
for(i=1;i<n;i++)
{
if(flag!=mul(sub(a[i],a[i-1]),sub(a[i+1],a[i])))
break;
}
if(i<n)
{
printf("HOLE IS ILL-FORMED\n");
continue;
}
for(i=0;i<n;i++)
{
if(flag!=mul(sub(a[i+1],a[i]),sub(peg,a[i])))
break;
if(dis(a[i],a[i+1])-r<0)
break;
}
if(i<n)
printf("PEG WILL NOT FIT\n");
else
printf("PEG WILL FIT\n");
}
return 0;
}