这场一开始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; }