首页 > 其他 > 详细

noip模拟测试20

时间:2019-08-14 22:15:54      阅读:91      评论:0      收藏:0      [点我收藏+]

T1:周(week)

  爆搜,完了……

技术分享图片
 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<iostream>
 6 #include<queue>
 7 #include<vector>
 8 #include<cstdlib>
 9 #define ll long long
10 using namespace std;
11 const int MAXN=50;
12 ll n,ans,a[MAXN],b[MAXN],c[MAXN],d[MAXN],sum[MAXN][2];
13 void dfs(int p) {
14     if(p==n+1) {
15         ans=max(ans,sum[n][0]*sum[n][1]);
16         return;
17     }
18     sum[p][0]=sum[p-1][0]+a[p];
19     sum[p][1]=max(sum[p-1][1]-b[p],0LL);
20     dfs(p+1);
21     sum[p][0]=max(sum[p-1][0]-d[p],0LL);
22     sum[p][1]=sum[p-1][1]+c[p];
23     dfs(p+1);
24 }
25 int main() {
26     scanf("%lld",&n);
27     for(int i=1;i<=n;i++)
28         scanf("%lld%lld%lld%lld",&a[i],&b[i],&c[i],&d[i]);
29     sum[0][0]=sum[0][1]=0LL;
30     dfs(1);
31     printf("%lld\n",ans);
32     return 0;
33 }
t1 Code

 


T2:任(duty)

  因为保证任意两个黑色像素之间最多只有一条简单路径,所以黑色点组成的应该是森林

  一个子矩形实际上就是割出一些树的一部分,同样也是森林

  我们的问题就转化为求一个森林中有几棵树

  可以用总点数减总边数得到

  所以我们只需要用子矩阵中的点数减去边数就行了

  那点数和边数该怎么快速求出呢?

  把边分为横纵两种,二维前缀和就完了……

技术分享图片
 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<iostream>
 6 #include<queue>
 7 #include<vector>
 8 #include<cstdlib>
 9 #define ll long long
10 using namespace std;
11 const int MAXN=2100;
12 int n,m,anse,ansp,q,er[MAXN][MAXN],ec[MAXN][MAXN],p[MAXN][MAXN];
13 char s[MAXN][MAXN];
14 int main() {
15     scanf("%d%d%d",&n,&m,&q);
16     for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
17     for(int i=1;i<=n;i++)
18         for(int j=1;j<=m;j++)
19             if(s[i][j]==1) p[i][j]=1;
20     for(int i=1;i<=n;i++)
21         for(int j=1;j<=m;j++)
22             p[i][j]=p[i][j]+p[i-1][j]+p[i][j-1]-p[i-1][j-1];
23     for(int i=1;i<=n;i++)
24         for(int j=1;j<m;j++)
25             if(s[i][j]==1&&s[i][j+1]==1) er[i][j]=1;
26     for(int i=1;i<=n;i++)
27         for(int j=1;j<m;j++)
28             er[i][j]=er[i][j]+er[i-1][j]+er[i][j-1]-er[i-1][j-1];
29     for(int i=1;i<n;i++)
30         for(int j=1;j<=m;j++)
31             if(s[i][j]==1&&s[i+1][j]==1) ec[i][j]=1;
32     for(int i=1;i<n;i++)
33         for(int j=1;j<=m;j++)
34             ec[i][j]=ec[i][j]+ec[i-1][j]+ec[i][j-1]-ec[i-1][j-1];
35     for(int i=1,aa,bb,cc,dd;i<=q;i++) {
36         scanf("%d%d%d%d",&aa,&bb,&cc,&dd);
37         ansp=p[cc][dd]-p[aa-1][dd]-p[cc][bb-1]+p[aa-1][bb-1];
38         anse=(er[cc][dd-1]-er[aa-1][dd-1]-er[cc][bb-1]+er[aa-1][bb-1])
39             +(ec[cc-1][dd]-ec[aa-1][dd]-ec[cc-1][bb-1]+ec[aa-1][bb-1]);
40         printf("%d\n",ansp-anse);
41     }
42     return 0;
43 }
t2 Code

 


T3:飞(fly)

  毒瘤题,卡空间……

  简单分析一下,发现两条线段相交当且仅当$y_a>y_b  \&\&  x_a<x_b$

  y还是连续的正整数

  ???

  这不就是简单的逆序对吗?

  不不不!空间开不下!!

  发现a很小,再看数据的生成方式是一个模意义下的等差数列

  于是可以在a上开树状数组,对于长度为a每段的数的分布应该是一样的,就可以算了

  (注意第一段等差数列比较特殊,需要特判)

技术分享图片
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cmath>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #define ll long long
 8 using namespace std;
 9 const int MAXA=1e5+233;
10 ll n,xx,a,D,now,cnt,d,ans,tr[MAXA];
11 void add(int x) {
12     for(++x;x<=a+1;x+=x&-x) ++tr[x];
13 }
14 ll ask(int x) {
15     ll ret=0;
16     for(++x;x;x-=x&-x) ret+=tr[x];
17     return ret;
18 }
19 int main() {
20     scanf("%lld%lld%lld%lld",&n,&xx,&a,&D);
21     now=xx;
22     for(int i=1;i<=n;i++) {
23         if(now<a) add(now),d=i-ask(now),ans+=d;
24         else {
25             d-=cnt;
26             if(now<xx) ++d;
27             ans+=d;
28         }
29         now+=a;
30         if(now>=D) now-=D,++cnt;
31     }
32     printf("%lld\n",ans);
33     return 0;
34 }
t3 Code

 

noip模拟测试20

原文:https://www.cnblogs.com/Gkeng/p/11354497.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!