[NOIP模拟测试31]题解
A.math
考场乱搞拿了95,2333。
考虑裴蜀定理:$ax+by=z$存在整数解,当且仅当$gcd(a,b)|z$。
那么如果某个数能够被拼出来,就必须满足所有$a_i$的$gcd$是它的因子。直接枚举倍数即可。
//代码来自DeepinC
#include<cstdio>
int n,k,g,x;
int gcd(int a,int b){return b?gcd(b,a%b):a;}
int main(){
scanf("%d%d",&n,&k);g=k;
while(n--)scanf("%d",&x),g=gcd(g,x);
printf("%d\n",k/g);
for(int i=0;i<k;i+=g)printf("%d ",i);
}
B.biology
首先将$a[i][j]$离散化,值相同的方格坐标都放到一起。然后很容易得到一个暴力的dp:$f[i][j]=max{f[i'][j']+|i-i'|+|j-j'|}$,$i',j'$位于a值比$i,j$小的上一层。
最劣复杂度会达到$O(n^2m^2)$,考虑优化。可以把绝对值用分类讨论拆开,四个树状数组分别维护$f[i][j]-i-j,f[i][j]-i+j,f[i][j]+i-j,f[i][j]+i+j$的最大值,转移时先分别查询以$i,j$为中心的四块区域的最优值,用最大的更新$f[i][j]$,之后再分别把$f[i][j]$上传到树状数组里。注意要用前缀最大值查询四块的最优值来保证log的复杂度,所以需要把坐标反转一下。
正解其实就是把树状数组去掉……我们用树状数组维护四部分的最大值是为了保证在合法的情况下转移最优,但本题的特殊性使不合法的情况一定没有合法情况优(如果你绝对值去的不对就会让坐标差变成负的),所以直接用四个变量维护四部分的最大值即可。我把坐标转换了一下,即$(i,j)->(i+j,i-j)$,其实不转换也是可以的。
//80分树状数组
#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#define pa pair<int,int>
#define QWQ dp[x][y]=max(dp[x][y],maxx)
using namespace std;
typedef long long ll;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return x*f;
}
const int N=2005,M=1e6+5;
int n,m;
int a[N][N],b[N][N];
struct bit
{
ll c[N][N];
int lb(int x){return x&-x;}
void update(int x,int y,ll val)
{
for(int i=x;i<=n;i+=lb(i))
for(int j=y;j<=m;j+=lb(j))
c[i][j]=max(val,c[i][j]);
}
ll query(int x,int y)
{
ll res=0;
for(int i=x;i;i-=lb(i))
for(int j=y;j;j-=lb(j))
res=max(res,c[i][j]);
return res;
}
}c1,c2,c3,c4;
int app[M],key[M],cnt,num[M];
vector<pa> fl[M];
ll dp[N][N];
int main()
{
n=read();m=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
a[i][j]=read();
if(!app[a[i][j]]&&a[i][j])
{
app[a[i][j]]=1;
num[++cnt]=a[i][j];
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
b[i][j]=read();
sort(num+1,num+cnt+1);
for(int i=1;i<=cnt;i++)
key[num[i]]=i;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(!a[i][j])continue;
fl[key[a[i][j]]].push_back(make_pair(i,j));
}
int sz=fl[1].size();
for(int i=0;i<sz;i++)
{
int x=fl[1][i].first,y=fl[1][i].second;
c1.update(x,y,b[x][y]-x-y);
c2.update(x,m-y+1,b[x][y]-x+y);
c3.update(n-x+1,y,b[x][y]+x-y);
c4.update(n-x+1,m-y+1,b[x][y]+x+y);
}
for(int i=2;i<=cnt;i++)
{
sz=fl[i].size();
for(int j=0;j<sz;j++)
{
int x=fl[i][j].first,y=fl[i][j].second;
ll maxx=0;
maxx=c1.query(x,y)+x+y+b[x][y];QWQ;
maxx=c2.query(x,m-y+1)+x-y+b[x][y];QWQ;
maxx=c3.query(n-x+1,y)-x+y+b[x][y];QWQ;
maxx=c4.query(n-x+1,m-y+1)-x-y+b[x][y];QWQ;
//cout<<x<<' '<<y<<' '<<dp[x][y]<<endl;
}
for(int j=0;j<sz;j++)
{
int x=fl[i][j].first,y=fl[i][j].second;
c1.update(x,y,dp[x][y]-x-y);
c2.update(x,m-y+1,dp[x][y]-x+y);
c3.update(n-x+1,y,dp[x][y]+x-y);
c4.update(n-x+1,m-y+1,dp[x][y]+x+y);
//cout<<x<<' '<<y<<' '<<dp[x][y]<<endl;
}
}
sz=fl[cnt].size();
ll ans=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
ans=max(ans,dp[i][j]);
cout<<ans<<endl;
return 0;
}
//AC
#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#define pa pair<int,int>
using namespace std;
typedef long long ll;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return x*f;
}
const int N=2005,M=1e6+5;
int n,m;
int a[N][N],b[N][N];
int app[M],key[M],cnt,num[M];
vector<pa> fl[M];
ll dp[N][N];
int getx(int i,int j){return (i+j)/2;}
int gety(int i,int j){return (i-j)/2;}
int main()
{
n=read();m=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
a[i][j]=read();
if(!app[a[i][j]]&&a[i][j])
{
app[a[i][j]]=1;
num[++cnt]=a[i][j];
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
b[i][j]=read();
sort(num+1,num+cnt+1);
for(int i=1;i<=cnt;i++)
key[num[i]]=i;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(!a[i][j])continue;
fl[key[a[i][j]]].push_back(make_pair(i+j,i-j));
}
ll c1=-0x3f3f3f3f,c2=-0x3f3f3f3f,c3=-0x3f3f3f3f,c4=-0x3f3f3f3f;
int sz=fl[1].size();
for(int i=0;i<sz;i++)
{
int x=fl[1][i].first,y=fl[1][i].second,ox=getx(x,y),oy=gety(x,y);
c1=max(c1,1LL*b[ox][oy]-x);
c2=max(c2,1LL*b[ox][oy]+x);
c3=max(c3,1LL*b[ox][oy]-y);
c4=max(c4,1LL*b[ox][oy]+y);
}
for(int i=2;i<=cnt;i++)
{
sz=fl[i].size();
for(int j=0;j<sz;j++)
{
int x=fl[i][j].first,y=fl[i][j].second,ox=getx(x,y),oy=gety(x,y);
ll maxx=max(max(c1+ox+oy,c2-ox-oy),max(c3+ox-oy,c4-ox+oy));
dp[ox][oy]=maxx+b[ox][oy];
}
for(int j=0;j<sz;j++)
{
int x=fl[i][j].first,y=fl[i][j].second,ox=getx(x,y),oy=gety(x,y);
c1=max(c1,dp[ox][oy]-x);
c2=max(c2,dp[ox][oy]+x);
c3=max(c3,dp[ox][oy]-y);
c4=max(c4,dp[ox][oy]+y);
}
}
ll ans=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
ans=max(ans,dp[i][j]);
cout<<ans<<endl;
return 0;
}
C.english
对于每一个$i\in n$,求出$a[i]$作为最大值的范围$[l,r]$,可以用单调栈实现。
维护一个前缀和,$f[x][i]$表示1~x的区间里第i位是1的数有多少个。
用启发式合并的思路,对于每一个区间x,看它的左右儿子区间$[l,x-1]$和$[x+1,r]$哪个长度更大,以右儿子长度大为例:
枚举左区间的每一个数$a[i]$,并枚举它的每一位,如果这一位是0,那么对ans1的贡献就是$2^i \times (f[r][i]-f[x-1]) \times a[x]$。如果是1同理。
对ans2的贡献就是右区间中有多少个数$xor\ a[i]$后$>a[x]$,再乘上$a[x]$。区间问题用可持久化Trie解决。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<stack>
#include<algorithm>
#include<map>
//#define int long long
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
typedef long long ll;
const int N=1e5+5;
const ll mod=1e9+7;
int n,a[N],op;
int le[N],re[N];
ll f[N][22];
stack<int> s;
ll ans1,ans2;
namespace Trie
{
int ch[N*22][2],size[N*22],type,root[N];
void ins(int pre,int &now,int i,ll x)
{
now=++type;
size[now]=size[pre];
if(i<0){size[now]++;return ;}
int d=(x>>i)&1;
ch[now][d^1]=ch[pre][d^1];
ins(ch[pre][d],ch[now][d],i-1,x);
size[now]=size[ch[now][0]]+size[ch[now][1]];
return ;
}
void ins(ll x,int pos){ins(root[pos-1],root[pos],20,x);}
ll query(int x,int y,int pos)
{
int p=root[pos],res=0;
for(int i=20;i>=0;i--)
{
int a=(x>>i)&1,b=(y>>i)&1;
if(b==0)
{
res+=size[ch[p][a^1]];
p=ch[p][a];
}
else p=ch[p][a^1];
if(!p)break;
}
return res;
}
}
void cacl(int k,int l,int r)
{
if(k-l<r-k)
{
for(int j=l;j<=k;j++)
{
(ans1+=1LL*a[j]*a[k]%mod*(r-k+1)%mod)%=mod;
for(int i=20;i>=0;i--)
{
int now=(a[j]>>i)&1;
if(!now)(ans1+=1LL*(1<<i)*(f[r][i]-f[k-1][i])%mod*a[k]%mod)%=mod;
else (ans1-=1LL*(1<<i)*(f[r][i]-f[k-1][i])%mod*a[k]%mod)%=mod,ans1=(ans1+mod)%mod;
}
ans2=(ans2+1LL*(Trie::query(a[j],a[k],r)-Trie::query(a[j],a[k],k-1)+mod)%mod*a[k]%mod)%mod;
}
}
else
{
for(int j=k;j<=r;j++)
{
(ans1+=1LL*a[j]*a[k]%mod*(k-l+1)%mod)%=mod;
for(int i=20;i>=0;i--)
{
int now=(a[j]>>i)&1;
if(!now)(ans1+=1LL*(1<<i)*(f[k][i]-f[l-1][i])%mod*a[k]%mod)%=mod;
else (ans1-=1LL*(1<<i)*(f[k][i]-f[l-1][i])%mod*a[k]%mod)%=mod,ans1=(ans1+mod)%mod;
}
ans2=(ans2+1LL*(Trie::query(a[j],a[k],k)-Trie::query(a[j],a[k],l-1)+mod)%mod*a[k]%mod)%mod;
}
}
} signed main()
{
n=read();op=read();
for(int i=1;i<=n;i++)
a[i]=read(),Trie::ins(a[i],i);
for(int i=1;i<=n;i++)
{
for(int j=0;j<=20;j++)
{
f[i][j]+=f[i-1][j];
if((a[i]>>j)&1)f[i][j]++;
}
}
for(int i=1;i<=n;i++)
{
while(!s.empty()&&a[i]>a[s.top()])s.pop();
le[i]=s.empty()?1:s.top()+1;
s.push(i);
}
while(!s.empty())s.pop();
for(int i=n;i;i--)
{
while(!s.empty()&&a[i]>=a[s.top()])s.pop();
re[i]=s.empty()?n:s.top()-1;
s.push(i);
}
for(int i=1;i<=n;i++)
cacl(i,le[i],re[i]);
if(op==1||op==3)cout<<ans1<<endl;
if(op==2||op==3)cout<<ans2<<endl;
/*for(int i=1;i<=n;i++)
cout<<i<<' '<<le[i]<<' '<<re[i]<<endl;*/
return 0;
}
/*
g++ -std=c++11 1.cpp -o 1
./1
*/
[NOIP模拟测试31]题解的更多相关文章
- [NOIP模拟测试38]题解
来自达哥的问候…… A.金 显然本题的考察点在于高精而不是裴蜀定理 根据裴蜀定理易得答案为Yes当且仅当$gcd(n,m)=1$,那么考虑怎么在高精度下判互质. 如果$n,m$都能被2整除,那么显然不 ...
- [NOIP模拟测试30]题解
A.Return 出题人大概是怕自己的中文十级没人知道,所以写了这么一个***题面.可能又觉得这题太水怕全场A掉后自己面子过不去,于是又故意把输出格式说的含糊不清.(鬼知道"那么输出-1&q ...
- [NOIP模拟测试12]题解
A. 找规律题.儿子的编号减去 小于它编号的最大的fibonacci数 即可得到它父亲的编号. 然后两个节点都暴力上跳就好了.预处理一下fibonacci数,每次二分查找即可. #include< ...
- [NOIP模拟测试11] 题解
A.string 和河北的一道省选题很像.考场上写的暴力桶排,正解其实就是优化一下这个思路. 开线段树维护字符串中每个字母出现的次数.对于每条询问,区间查询.区间赋值维护即可. 另外,本题卡常严重,正 ...
- noip模拟测试31
终于有时间写博客了,前面一直咕咕咕都快变成一只公鸡了......这次考试,真的很意外,我在考场上觉得自己打出了T1的正解,样例一拍就过,还跑得嘎嘎快,然后T2,T3码了两个暴力,觉得自己应该能100p ...
- 「题解」NOIP模拟测试题解乱写II(36)
毕竟考得太频繁了于是不可能每次考试都写题解.(我解释个什么劲啊又没有人看) 甚至有的题目都没有改掉.跑过来写题解一方面是总结,另一方面也是放松了. NOIP模拟测试36 T1字符 这题我完全懵逼了.就 ...
- 2019.8.3 [HZOI]NOIP模拟测试12 C. 分组
2019.8.3 [HZOI]NOIP模拟测试12 C. 分组 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 刚看这题觉得很难,于是数据点分治 k只有1和2两种,分别 ...
- 2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色
2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 数据结构学傻的做法: 对每种颜色开动态开点线段树直接维 ...
- 2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci)
2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci) 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 找规律 找两个节点的lca,需 ...
随机推荐
- CF 1172E Nauuo and ODT ——LCT
题目:http://codeforces.com/contest/1172/problem/E LCT好题. 考虑对每个颜色求出 “不是该颜色的点组成的连通块的 siz2 之和” .每个颜色用 LCT ...
- 启动Nginx、查看nginx进程、nginx帮助命令、Nginx平滑重启、Nginx服务器的升级
1.启动nginx的方式: cd /usr/local/nginx ls
- jerry
jerry 题目描述 众所周知,Jerry 鼠是一只非常聪明的老鼠. Jerry 聪明到它可以计算64 位有符号整形数字的加减法. 现在,Jerry 写下了一个只由非负整数和加减号组成的算式.它想给这 ...
- 前端每日实战:29# 视频演示如何不用 transition 和 animation 也能做网页动画
效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/BxbQJj 可交互视频教程 此视频 ...
- kPagination纯js实现分页插件
kPagination分页插件 纯js分页插件,压缩版本~4kb,样式可以自定义 demo 使用方法 <div id="pagination"></div> ...
- linux内核,驱动,应用程三者的概念和之间的关系
驱动程序属于内核的一个部分.准确的说是内核的一个组件.不包含驱动的内核也叫做内核,并且这也是我们常说的内核.内核要干的事情无非5件. 1,内存管理 2,虚拟文件系统 3,进程调度 4,网络接口 5,进 ...
- spring boot 尚桂谷学习笔记09 数据访问
springboot 与数据库访问 jdbc, mybatis, spring data jpa, 1.jdbc原生访问 新建项目 使用 springboot 快速构建工具 选中 web 组件 sq ...
- 洛谷P4169 [Violet]天使玩偶/SJY摆棋子(CDQ分治)
[Violet]天使玩偶/SJY摆棋子 题目传送门 解题思路 用CDQ分治开了氧气跑过. 将输入给的顺序作为第一维的时间,x为第二维,y为第三维.对于距离一个询问(ax,ay),将询问分为四块,左上, ...
- B. pSort
题目链接: http://codeforces.com/problemset/problem/28/B 题意: 给一个n,原本有个1到n按顺序排列的序列,给一个序列问,在给一个数组,表示这个位置的数可 ...
- git笔记十:本地仓库同步到gitlab
本地仓库同步到gitlab 帮助文档 git remote --help 操作场景: 本地创建git仓库(含有readme.md文件), commit了三次 gitlab网站创建了一个项目 添加了re ...