2017/10/21模拟赛总结
来源:互联网 发布:淘宝链接转换淘口令 编辑:程序博客网 时间:2024/06/05 03:17
T1 完美01正方形
枚举端点前缀和判断一下就好了
注意判断的条件
#include<bits/stdc++.h>using namespace std;#define N 310int a[N][N];int calc(int l1,int l2,int r1,int r2){ return a[l2][r2]-a[l1-1][r2]-a[l2][r1-1]+a[l1-1][r1-1];}int main(){ int n,m,i,j,k,ans=0; scanf("%d%d",&n,&m); for (i=1;i<=n;i++) for (j=1;j<=m;j++){ scanf("%d",&a[i][j]); a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1]; } for (i=1;i<=n;i++) for (j=1;j<=m;j++) for (k=1;k+i<=n && k+j<=m;k++){ int i1=i+k,j1=j+k; if (calc(i,i1,j,j)!=k+1) continue; if (calc(i,i1,j1,j1)!=k+1) continue; if (calc(i,i,j,j1)!=k+1) continue; if (calc(i1,i1,j,j1)!=k+1) continue; if (calc(i+1,i1-1,j+1,j1-1)!=(k-1)*(k-1)/2 && calc(i+1,i1-1,j+1,j1-1)!=((k-1)*(k-1)+1)/2) continue; ans++; } printf("%d\n",ans); return 0;}
T2 重温LIS
可以从左到右 从右到左各做一遍LIS
如果左右LIS相加长度等于整个LIS 那么就说明在LIS上
如果左右LIS方案数相乘等于整个LIS的方案数 说明这个点在所有的LIS上
由于方案数巨大 可以对质数取模
#include<bits/stdc++.h>using namespace std;#define N 100010#define mo 1000000007int a[N],f[N],lis,n;long long lisnum,g[N];void cmp(int &x,long long &y,int x1,long long y1){ if (x<x1) x=x1,y=y1; else if (x==x1) y=(y+y1)%mo;}struct Binary_Indexed_Tree_1{ int bit[N]; long long num[N]; void add(int i,int x,long long y){ while (i<N){ cmp(bit[i],num[i],x,y); i+=i&-i; } } void query(int i,int &res1,long long &res2){ res1=res2=0; while (i){ cmp(res1,res2,bit[i],num[i]); i-=i&-i; } }}BIT1;struct Binary_Indexed_tree_2{ int bit[N]; long long num[N]; void add(int i,int x,long long y){ while (i){ cmp(bit[i],num[i],x,y); i-=i&-i; } } void query(int i,int &res1,long long &res2){ res1=res2=0; while (i<N){ cmp(res1,res2,bit[i],num[i]); i+=i&-i; } }}BIT2;int ans[N];int main(){ int i; scanf("%d",&n); for (i=1;i<=n;i++){ scanf("%d",&a[i]); BIT1.query(a[i]-1,f[i],g[i]); if (!f[i]) g[i]++; f[i]++; BIT1.add(a[i],f[i],g[i]); cmp(lis,lisnum,f[i],g[i]); } for (i=n;i;i--){ int sum1; long long sum2; BIT2.query(a[i]+1,sum1,sum2); if (!sum1) sum2++; if (sum1+f[i]==lis){ if (g[i]*sum2%mo==lisnum) ans[i]=3; else ans[i]=2; }else ans[i]=1; BIT2.add(a[i],sum1+1,sum2); } for (i=1;i<=n;i++) printf("%d",ans[i]); return 0;}
T3 画画
解法1
首先可以想到用二分最大值 把本题变成一个判定性问题
有了最大值 肯定是尽可能往后跳 用尺取预处理出第一行 第二行 两行从一个位置开始最多跳到哪里
分三种情况讨论即可
考虑把两个情况放在一起考虑 即
每次最多往前跳
然后从较大的那个地方转移(因为不知道覆盖较小的那个地方还需要多少画)
实现细节见代码
#include<bits/stdc++.h>using namespace std;#define N 500010#define INF (0x3f3f3f3f3f3f3f3f)void rd(int &x){ char c;x=0; while (c=getchar(),c<48); do x=(x<<1)+(x<<3)+(c^48); while (c=getchar(),c>=48);}int a[N],b[N],n,m;long long suma[N],sumb[N];struct P3{ int dp[N],f[N],g[N],h[N]; bool check(long long x){ int i,j,k; int l,r; for (l=0,r=1;r<=n;r++){ while (suma[r]-suma[l]>x) l++; f[r]=l; } for (l=0,r=1;r<=n;r++){ while (sumb[r]-sumb[l]>x) l++; g[r]=l; } for (l=0,r=1;r<=n;r++){ while (suma[r]-suma[l]+sumb[r]-sumb[l]>x) l++; h[r]=l; } memset(dp,63,sizeof(dp)); dp[0]=0; for (i=1;i<=n;i++){ dp[i]=dp[h[i]]+1; j=i,k=i; int cnt=0; while (cnt<m && (j || k)){ cnt++; if (j>=k) j=f[j]; else k=g[k]; dp[i]=min(dp[i],dp[max(j,k)]+cnt); } } return dp[n]<=m; } void solve(){ long long l=1,r=suma[n]+sumb[n]; long long res=r; while (l<=r){ int mid=(l+r)>>1; if (check(mid)) res=mid,r=mid-1; else l=mid+1; } printf("%lld\n",res); }}P100;int main(){ int i; rd(n),rd(m); for (i=1;i<=n;i++) rd(a[i]),suma[i]=suma[i-1]+a[i]; for (i=1;i<=n;i++) rd(b[i]),sumb[i]=sumb[i-1]+b[i]; P100.solve(); return 0;}
解法2
考虑用画的数量定义 即
类似上面的方法向后跳
#include<bits/stdc++.h>using namespace std;#define N 20010#define M 110#define INF (0x3f3f3f3f3f3f3f3f)void rd(int &x){ char c;x=0; while (c=getchar(),c<48); do x=(x<<1)+(x<<3)+(c^48); while (c=getchar(),c>=48);}int a[N],b[N],n,m;long long suma[N],sumb[N];struct P3{ int dp[M],f[N],g[N],h[N]; bool check(long long x){ int i,j,k; int l,r; for (l=0,r=1;l<=n;l++){ while (r<n && suma[r+1]-suma[l]<=x) r++; f[l]=r; } for (l=0,r=1;l<=n;l++){ while (r<n && sumb[r+1]-sumb[l]<=x) r++; g[l]=r; } for (l=0,r=1;l<=n;l++){ while (r<n && suma[r+1]-suma[l]+sumb[r+1]-sumb[l]<=x) r++; h[l]=r; } memset(dp,0,sizeof(dp)); dp[0]=0; for (i=0;i<m;i++){ j=k=dp[i]; dp[i+1]=max(dp[i+1],h[j]); int cnt=0; while (i+cnt<m && (j<n || k<n)){ cnt++; if (j<=k) j=f[j]; else k=g[k]; dp[i+cnt]=max(dp[i+cnt],min(j,k)); } } return dp[m]==n; } void solve(){ long long l=1,r=suma[n]+sumb[n]; long long res=r; while (l<=r){ int mid=(l+r)>>1; if (check(mid)) res=mid,r=mid-1; else l=mid+1; } printf("%lld\n",res); }}P100;int main(){ int i; rd(n),rd(m); for (i=1;i<=n;i++) rd(a[i]),suma[i]=suma[i-1]+a[i]; for (i=1;i<=n;i++) rd(b[i]),sumb[i]=sumb[i-1]+b[i]; P100.solve(); return 0;}
这次T2和T3都是从经典问题提升而来的 解题时应该要考虑以前的解决方式 加以改进和优化
Date:2017/10/23
By CalvinJin
阅读全文
0 0
- 2017/10/21模拟赛总结
- 2017/10/10模拟赛总结
- 2017/10/7模拟赛总结
- 2017/10/9模拟赛总结
- 2017/10/6模拟赛总结
- 2017/10/12模拟赛总结
- 2017/10/15模拟赛总结
- 2017/10/16模拟赛总结
- 2017/10/23模拟赛总结
- 2017/10/25模拟赛总结
- 2017/10/30模拟赛总结
- 2016.5.21模拟赛总结
- NOIP2017模拟赛(10) 总结
- 2016.5.21初中部模拟赛总结
- 2016.5.21初中部模拟赛总结
- 2016.5.21初中部模拟赛总结
- 9-21NOIp模拟赛总结
- 2017/11/3模拟赛总结
- Django 重写user表
- 慢查优化
- 认识name属性
- Java中有关Null的9件事
- Windows下Node.js与npm的安装与配置
- 2017/10/21模拟赛总结
- 通过WM_COPYDATA消息完成进程间通信
- js展开一颗树
- String类
- python 同时迭代多个对象
- window下安装gensim
- form转json方法
- 设计模式
- # 在宏定义中的使用