这场一开始A题用set乱贪一发就交了,然后WA第六组。。。。然后二分乱搞过的。B题真的是想晕了,4秒的时限就是骗人的嘛。。。最后用1600*1600复杂度过的。。。思维不行,还需要好好练习。。。
A:
题意:
把一个袋鼠装进另一个袋鼠。每个袋鼠只能装一个袋鼠且必须体积小于等于自己的一半。不能装 装了袋鼠的袋鼠。求最少剩 多少只袋鼠。
思路:二分有多少只袋鼠被装。
code:
#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <math.h>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
#define N 500010
#define ALL(x) x.begin(),x.end()
#define CLR(x,a) memset(x,a,sizeof(x))
typedef long long ll;
typedef pair<int,int> PI;
const int INF = 0x3fffffff;
const int MOD = 100000007;
const double EPS = 1e-7;
int n;
int a[N];
bool check(int x)
{
for(int i=0;i<x;i++){
if(2*a[i]>a[n-x+i]) return false;
}
return true;
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
sort(a,a+n);
int l=0,r=n/2+1;
while(l<r){
int mid=(l+r)>>1;
if(check(mid)) l=mid+1;
else r=mid;
}
printf("%d\n",n-r+1);
return 0;
}
题意:求矩阵里有多少个子矩阵全包含零。
思路:dp[x0][y0][x1][y1] 表示矩阵{x0<=x<=x1,y0<=y<=y1}有多少个包含1的矩阵,tot[x0][y0][x1][y1]则表示有多少个子矩阵,对减下就是答案,递推的方法看代码,类似容斥。
比赛的时候没有去递推tot,一直以为是算一下组合数就是了,然后狂卡样例。。。。真是弱。。代码略翔,递推太长了。
code:
#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <math.h>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
#define N 500010
#define ALL(x) x.begin(),x.end()
#define CLR(x,a) memset(x,a,sizeof(x))
typedef long long ll;
typedef pair<int,int> PI;
const int INF = 0x3fffffff;
const int MOD = 100000007;
const double EPS = 1e-7;
int n,m;
int sum[64][64][64][64];
int tot[64][64][64][64];
int main()
{
int x0,x1,y0,y1;
scanf("%d%d",&n,&m);
int Q;
scanf("%d",&Q);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
scanf("%1d",&sum[i][j][i][j]);
tot[i][j][i][j]=1;
}
for(int h=1;h<=n;h++){
for(int w=1;w<=m;w++){
if(h==1 && w==1) continue;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
int k=i+h-1,q=j+w-1;
if(k>n || q>m) break;
sum[i][j][k][q]+=sum[i+1][j][k][q]+sum[i][j+1][k][q]+sum[i][j][k-1][q]
+sum[i][j][k][q-1];
sum[i][j][k][q]-=sum[i+1][j+1][k][q]+sum[i+1][j][k-1][q]+sum[i+1][j][k][q-1]
+sum[i][j+1][k-1][q]+sum[i][j+1][k][q-1]+sum[i][j][k-1][q-1];
sum[i][j][k][q]+=sum[i+1][j+1][k-1][q]+sum[i+1][j+1][k][q-1]
+sum[i+1][j][k-1][q-1]+sum[i][j+1][k-1][q-1];
sum[i][j][k][q]-=sum[i+1][j+1][k-1][q-1];
sum[i][j][k][q]+=(sum[i][j][k][q]>0);
tot[i][j][k][q]+=tot[i+1][j][k][q]+tot[i][j+1][k][q]+tot[i][j][k-1][q]
+tot[i][j][k][q-1];
tot[i][j][k][q]-=tot[i+1][j+1][k][q]+tot[i+1][j][k-1][q]+tot[i+1][j][k][q-1]
+tot[i][j+1][k-1][q]+tot[i][j+1][k][q-1]+tot[i][j][k-1][q-1];
tot[i][j][k][q]+=tot[i+1][j+1][k-1][q]+tot[i+1][j+1][k][q-1]
+tot[i+1][j][k-1][q-1]+tot[i][j+1][k-1][q-1];
tot[i][j][k][q]-=tot[i+1][j+1][k-1][q-1];
tot[i][j][k][q]++;
}
}
}
}
while(Q--){
scanf("%d%d%d%d",&x0,&y0,&x1,&y1);
printf("%d\n",tot[x0][y0][x1][y1]-sum[x0][y0][x1][y1]);
}
return 0;
}
C:
题意:
有n个看台排成一条直线。现在要放m次烟花。每次放烟花,你会获得b-|a-x|的收益,a表示烟花在哪个看台放,x是你所在的位置。每单位时间你最多能移动距离d,给出了每组烟花燃放的时间,求最大收益。
思路:
dp[i][j] 表示燃放第i组烟花,此时人在第j个看台时候的最大收益。
用dis表示从i-1到i最多能移动的距离,那么转移就是dp[i][j]=max{dp[i-1][k] | abs(j-k)<=dis }。用单调队列优化下,就能过了。
code:
#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <math.h>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
#define N 200010
#define ALL(x) x.begin(),x.end()
#define CLR(x,a) memset(x,a,sizeof(x))
typedef long long ll;
typedef pair<int,int> PI;
const int INF = 0x3fffffff;
const int MOD = 100000007;
const double EPS = 1e-7;
deque<int> que;
ll dp[2][N];
int main()
{
int n,m,d,pret=0,pre=1,now=0;
int a,b,t;
scanf("%d%d%d",&n,&m,&d);
for(int i=0;i<m;i++){
scanf("%d%d%d",&a,&b,&t);
ll dis=1ll*d*(t-pret);
pret=t;
que.clear();
for(int j=1;j<=n;j++){
while(!que.empty() && dp[pre][j]>dp[pre][que.back()]) que.pop_back();
que.push_back(j);
while(dis<abs(que.front()-j)) que.pop_front();
dp[now][j]=dp[pre][que.front()];
}
que.clear();
for(int j=n;j>=1;j--){
while(!que.empty() && dp[pre][j]>dp[pre][que.back()]) que.pop_back();
que.push_back(j);
while(dis<abs(que.front()-j)) que.pop_front();
dp[now][j]=max(dp[now][j],dp[pre][que.front()]);
}
for(int j=1;j<=n;j++) dp[now][j]+=b-abs(j-a);
swap(pre,now);
}
printf("%I64d\n",*max_element(dp[pre]+1,dp[pre]+n+1));
return 0;
}