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. vue.js样式绑定

    vue.js样式绑定 class 与 style 是 HTML 元素的属性,用于设置元素的样式,我们可以用 v-bind 来设置样式属性. Vue.js v-bind 在处理 class 和 styl ...

  2. NOIp 图论算法专题总结 (2)

    系列索引: NOIp 图论算法专题总结 (1) NOIp 图论算法专题总结 (2) NOIp 图论算法专题总结 (3) 树链剖分 https://oi-wiki.org/graph/heavy-lig ...

  3. zkw 线段树

    优秀的 zkw 线段树讲解:<线段树的扩展之浅谈 zkw 线段树> 存一份模板代码(区间修改.区间查询): /* zkw Segment Tree * Au: GG */ #include ...

  4. python删除列表中得重复得数据

    解决思想:将列表转换为 集合,利用集合删除重复数据得特性删除重复数据,然后将集合转换为列表 #删除列表中得重复元素 def delect_1 (lt): s = set(lt) lt = list(s ...

  5. mac使用相关笔记

    1.软件提示已损坏,需要移到废纸篓的解决方法 -> sudo spctl --master-disable xattr -r -d com.apple.quarantine <path&g ...

  6. C++ win32 dll 引用外部CLR,加载托管程序集异常-Error 10 error LNK2019: unresolved external symbol _CLRCreateInstancet

    异常: Error 10 error LNK2019: unresolved external symbol _CLRCreateInstance@12 referenced in function ...

  7. jenkins实现master变化时,才触发构建(过滤分支)

    现状:现在是这样的,每个开发push时,都触发jenkins进行构建 期望:只有当代码被push到master时才进行构建 (根据使用的git平台)做这些配置需要先了解一些概念: (github) p ...

  8. 重温《javascript高级程序设计》(第3版)

    1.重温<JavaScript高级程序设计>(第3版) (一)重温<javascript高级程序设计>(第1-4章) (二)重温<JavaScript高级程序设计> ...

  9. django-5-使用数据库

    修改默认数据库 django默认数据库为 SQLite3,若需要修改,比如改成mysql,则需要修改与settings.py文件同路径的__init__.py文件,添加如下内容: import pym ...

  10. lua脚本分解字符串

    --local str = "文字45 文字 789 文们adsd45 文字 wowo 文字 文字 wowo我们 wowo456 wiwo 465我们 456sdf 45 45我们adsd4 ...