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]题解的更多相关文章

  1. [NOIP模拟测试38]题解

    来自达哥的问候…… A.金 显然本题的考察点在于高精而不是裴蜀定理 根据裴蜀定理易得答案为Yes当且仅当$gcd(n,m)=1$,那么考虑怎么在高精度下判互质. 如果$n,m$都能被2整除,那么显然不 ...

  2. [NOIP模拟测试30]题解

    A.Return 出题人大概是怕自己的中文十级没人知道,所以写了这么一个***题面.可能又觉得这题太水怕全场A掉后自己面子过不去,于是又故意把输出格式说的含糊不清.(鬼知道"那么输出-1&q ...

  3. [NOIP模拟测试12]题解

    A. 找规律题.儿子的编号减去 小于它编号的最大的fibonacci数 即可得到它父亲的编号. 然后两个节点都暴力上跳就好了.预处理一下fibonacci数,每次二分查找即可. #include< ...

  4. [NOIP模拟测试11] 题解

    A.string 和河北的一道省选题很像.考场上写的暴力桶排,正解其实就是优化一下这个思路. 开线段树维护字符串中每个字母出现的次数.对于每条询问,区间查询.区间赋值维护即可. 另外,本题卡常严重,正 ...

  5. noip模拟测试31

    终于有时间写博客了,前面一直咕咕咕都快变成一只公鸡了......这次考试,真的很意外,我在考场上觉得自己打出了T1的正解,样例一拍就过,还跑得嘎嘎快,然后T2,T3码了两个暴力,觉得自己应该能100p ...

  6. 「题解」NOIP模拟测试题解乱写II(36)

    毕竟考得太频繁了于是不可能每次考试都写题解.(我解释个什么劲啊又没有人看) 甚至有的题目都没有改掉.跑过来写题解一方面是总结,另一方面也是放松了. NOIP模拟测试36 T1字符 这题我完全懵逼了.就 ...

  7. 2019.8.3 [HZOI]NOIP模拟测试12 C. 分组

    2019.8.3 [HZOI]NOIP模拟测试12 C. 分组 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 刚看这题觉得很难,于是数据点分治 k只有1和2两种,分别 ...

  8. 2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色

    2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 数据结构学傻的做法: 对每种颜色开动态开点线段树直接维 ...

  9. 2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci)

    2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci) 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 找规律 找两个节点的lca,需 ...

随机推荐

  1. 【HDOJ6604】Blow up the city(支配树)

    题意:给定一个n点m边的DAG,将只有入边的点称为周驿东点 q次询问,每次给定a,b两点,询问删去某个点x和其相连的所有边,能使a,b至少其中之一不能到达任何周驿东点的x的个数 n,q<=1e5 ...

  2. flutter页面布局三

    RaisedButton 为了实现今天的效果,在认识Wrap组件之前,先认识一下flutter中的按钮组件,Flutter 中通过 RaisedButton 定义一个按钮. import 'packa ...

  3. LUOGU P4088 [USACO18FEB]Slingshot(线段树)

    传送门 解题思路 推了推式子发现是个二维数点,想了想似乎排序加线段树难写,就写了个树套树,结果写完看见空间才\(128M\)..各种奇技淫巧卡空间还是\(MLE\)到天上.后来只好乖乖的写排序+线段树 ...

  4. JS 中的offset、scroll、client总结

    经常碰到offset.scroll.client这几个关键字,每次都要各种实验,这里总结一下. 两张图镇楼,随时翻阅 1. offset offset 指偏移,包括这个元素在文档中占用的所有显示宽度, ...

  5. python rpy2,tkinter安装问题解决

    windows系统下 在python中直接pip install rpy2时,会出错,没仔细看错误,直接下载了whl文件(https://www.lfd.uci.edu/~gohlke/pythonl ...

  6. 数论---lcm和gcd

    cd即最大公约数,lcm即最小公倍数. 首先给出a×b=gcd×lcm 证明:令gcd(a,b)=k,a=xk,b=yk,则a×b=xykk,而lcm=xyk,所以ab=gcd*lcm. 所以求lcm ...

  7. FlowProtal jQuery 对比时间大小

    function ValidatoTime(source, args){ var StartTime = agent.calcExpress(null, 'SCTDB:AS_MeetingRoom.S ...

  8. JVM系列(二) — Java垃圾收集介绍

    这篇文章主要从以下几个方面介绍垃圾收集的相关知识 一.判断对象是否已死 二.主流垃圾收集算法 三.内存分配与回收策略 本章节主要从以下几个思考点着手介绍垃圾回收的相关知识:哪些内存需要回收?什么时候回 ...

  9. BCrypt密码加密

    快速入门 (1)我们从官网下载源码 BCrypt 官网 http://www.mindrot.org/projects/jBCrypt/ (2)新建工程,将源码类BCrypt拷贝到工程 (3)新建测试 ...

  10. 在学react时候找不到static/js/bundle.js

    看如图上面bundle.js,我在项目中和配置文件中都没有找到这个JS文件,然后我就觉得很诧异,然后各种查找,终于找到一篇文章,在此记录一下 第一步:npm run start            ...