超链接为pdf题面,请先登录。
本题正解是dp,没学过的,先做一下USACO的题目“数字金字塔”,会更好理解这题,
设 map[i][j] 为(1,1)到(i,j)的路径总数,设 bz[i][j] 为(i,j)是否有施工。
则 map[i][j]=map[i-1][j]+map[i][j-1],前提是 !bz[i][j]。
dp code:
#include
#include
#include
#include
using namespace std;
int map[20][20];
bool bz[20][20];
int a,b,n;
int main()
{
int k,x,y;
scanf("%d%d%d",&a,&b,&n);
memset(map,0,sizeof(map));
memset(bz,0,sizeof(bz));
for(int i=1;i<=n;i++)
{
scanf("%d%d",&x,&y);
bz[x][y]=true;
}
map[0][1]=true;
for(int i=1;i<=a;i++)
for(int j=1;j<=b;j++)
if(!bz[i][j])
map[i][j]=map[i-1][j]+map[i][j-1];
printf("%d\n",map[a][b]);
return 0;
//0ms 948kb
}
还能用搜索做,会略慢一些。
dfs code:
#include
#include
int n,m,ans=0;
int a[20][20];
int dx[2]={0,1};
int dy[2]={1,0};
struct nod{int x,y;}f[210000];
void dfs(int x,int y,int t)
{
if(x==n&&y==m)
ans++;
else
for(int i=0;i<=1;i++)
{
int xx=x+dx[i],yy=y+dy[i];
if(xx>=1&&yy>=1&&xx<=n&&yy<=m&&a[xx][yy]==0)
{
f[t].x=xx;f[t].y=yy;
a[xx][yy]=1;
dfs(xx,yy,t+1);
a[xx][yy]=0;
}
}
}
int main()
{
scanf("%d %d",&n,&m);
int c;
scanf("%d",&c);
memset(a,0,sizeof(a));
memset(f,0,sizeof(f));
for(int i=1;i<=c;i++)
{
int x,y;
scanf("%d %d",&x,&y);
a[x][y]=1;
}
dfs(1,1,0);
printf("%d",ans);
return 0;
//53ms 1.8mb
}
bfs code:
#include
//#include
//#include
using namespace std;
int queue[10000010][2];
int x,y;
int bx,by;
int n;
int map[17][17];
int zx[3]={0,1,0},zy[3]={0,0,1};
int bz[17][17];
int ans;
int main()
{
for(int i=1;i<=17;i++)
for(int j=1;j<=17;j++)
map[i][j]=true;
scanf("%d%d%d",&x,&y,&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&bx,&by);
map[bx][by]=false;
}
// bfs();
int head=0,tail=1;
queue[1][0]=1,queue[1][1]=1;
while(head<=tail)
{
head++;
// bx=queue[head][0],by=queue[head][1];
for(int i=1;i<=2;i++)
{
bx=queue[head][0]+zx[i],by=queue[head][1]+zy[i];
if(map[bx][by]==true&&(1<=bx&&bx<=x)&&(1<=by&&by<=y))
{
// bz[queue[head][0]][queue[head][1]]=true;
tail++;
if(bx==x&&by==y)
ans++;
else
queue[tail][0]=bx,queue[tail][1]=by;
// system("cls");
// for(int i=1;i<=x;i++)
// {
// for(int j=1;j<=y;j++)
// if(i==bx&&j==by)
// printf("*");
// else
// printf("%d",map[i][j]);
// printf("\n");
// }
// getch();
}
}
}
printf("%d\n",ans);
return 0;
//55ms 76.49MB
}
正解暴枚, 枚举任意两个点,画出第三和第四个点,判断是否存在。
eov code:
#include
#include
#define abs(a) ((a)>=0?(a):-(a))
#define max(a,b) ((a)>(b)?(a):(b))
long long int n,mx;
long long int x[5010],y[5010];
bool a[5010][5010];
using namespace std;
int main()
{
int x1=0,x2=0,y1=0,y2=0,s=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&x[i],&y[i]);
a[x[i]][y[i]]=true;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
x1=abs(y[i]-y[j])+x[i];
y1=abs(x[i]-x[j])+y[i];
x2=abs(y[i]-y[j])+x[j];
y2=abs(x[i]-x[j])+y[j];
if(x1<=5000&&x2<=5000&&y1<=5000&&y2<=5000)
{
s=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);
if(a[x1][y1]&&a[x2][y2])
mx=max(mx,s);
}
// if(s>mx)
// {
// if(a[x1][y1]&&a[x2][y2])
}
}
printf("%d\n",mx);
return 0;
//249 ms 24.21 MB
}
正解是拓扑排序,我查了一下,有一篇博客讲拓扑排序不错,不太会的能看一下。
看完之后,大家应该都对这题有思路了吧。
只要发现有两个入度为零的队伍的话,就得知有两个以上的胜负情况了。
TS code:
#include
#include
using namespace std;
struct node
{
int num,pai;
}s[5010];
bool cmpai(node a,node b)
{
return a.pai > b.pai || (a.pai == b.pai && a.num < b.num);
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
s[i].num=i;
for(int i=1;i<=m;i++)
{
int a,b;
scanf("%d%d",&a,&b);
s[b].pai=min(s[a].pai-1,s[b].pai);
}
sort(s+1,s+n+1,cmpai);
int ans=0;
for (int i=1;i<=n;i++)
{
if(s[i].pai==s[i=1].pai)
ans=1;
printf("%d\n",s[i].num);
}
printf("%d\n",ans);
return 0;
//22ms 240kb
}
这题考到了二叉树的运用,应该是这套比赛中最难的一题。
要想一个天平平衡,首先要使得左右天平两边平衡。假设左右两边的最轻重量 分别为W1,W2,设该天平左右两边的比例为L1:L2,要想使得该天平衡,可能左边要放大倍数 X,右边要放大倍数Y,则有以下关系式: W1XL1=W2L2Y;
即X/Y=(W2L2)/(W1L1),要想使天平重量最小,必须把X/Y化为最简分数,所以需要求出 W2L2和W1L1的最大公约数P,则X=W2L2 div P ,Y=W1L1 div P,整个天平的重量为 W1X+W2Y。
BT code:
#include
struct node
{
long long int p,q,r,b;
}a[110];
int n,ans;
long long int f[110];
bool p[110];
int gcd(int a,int b)
{
return (b==0)?(a):(gcd(b,a%b));
}
long long int dfs(int x)
{
int l=a[x].r,r=a[x].b;
long long int left=1,right=1;
if(l)
left=dfs(l);
if(r)
right=dfs(r);
int ans=(left*a[x].p*right*a[x].q)/gcd(left*a[x].p,right*a[x].q);
return ans/a[x].p+ans/a[x].q;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
scanf("%d%d%d%d",&a[i].p,&a[i].q,&a[i].r,&a[i].b);
p[a[i].r]=true;
p[a[i].b]=true;
}
for(int i=1;i<=n;++i)
if(!p[i])
{
ans=i;
break;
}
printf("%d\n",dfs(ans));
return 0;
//0ms 208kb
}
这题是 JZOJ 1347的升级版。
如果是 1347 的话,暴力可以过,只用枚举1,2的分界线就行了。
但是这一题,当然不能枚举1,2,3……n的分界线,绝对超时。
一下是一个复杂度为O(nlogn)的思路
思路:根据给出的队列找出最长不下降子序列的长度,输出队列总长度-最长不下降子序列长度即可
f[i]表示以a[i]为结尾的最长不下降子序列长度;
g[i]表示长度为i的不下降子序列的最后一位的最小值是多少(具体实现方法同最长不下降子序列)
因为发现手打最长不下降子序列会超时,所以用upper_bound实现logn的查找。
DP code:
#include
#include
using namespace std;
int n,ma,f[50010],g[50010],a[50010];
int main()
{
// freopen("diningb.in","r",stdin);
// freopen("diningb.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
f[i]=1;
g[i]=2e9;
}
for(int i=1;i<=n;i++)
{
int k=upper_bound(g+1,g+1+n,a[i])-g;//k是指针,所以最后别忘了减g(如果改为lower_bound则为上升子序列),k表示在数组中的位置
f[i]=k;
g[k]=a[i];
}
for(int i=1;i<=n;i++)
ma=max(ma,f[i]);
printf("%d\n",n-ma);
return 0;
//11ms 788kb
}
这个code使用于 1347 和 1351。