[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,需 ...
随机推荐
- C++ 使用STL string 实现的split,trim,replace-修订
写个小工具函数 #include <iostream> #include <vector> using namespace std; namespace strtool { s ...
- [CSP-S模拟测试]:密州盛宴(贪心)
江城子·密州出猎老夫聊发少年狂,左牵黄,右擎苍,锦帽貂裘,千骑卷平冈.为报倾城随太守,亲射虎,看孙郎.酒酣胸胆尚开张,鬓微霜,又何妨!持节云中,何日遣冯唐?会挽雕弓如满月,西北望,射天狼.(这首词通过 ...
- 认识setFactory
平常设置或者获取一个View时,用的较多的是setContentView或LayoutInflater#inflate,setContentView内部也是通过调用LayoutInflater#inf ...
- (转)教你分分钟搞定Docker私有仓库Registry
转:https://www.cnblogs.com/Javame/p/7389093.html 一.什么是Docker私有仓库Registry 官方的Docker hub是一个用于管理公共镜像的好地方 ...
- linux记事工具:RedNotebook Lifeograph Kontact ThotKeeper
Linux桌面有许多灵活而功能强大的日记工具,如支持标签.加密.多种日志模版和实时搜索.其中的优秀者包括: RedNotebook Lifeograph Kontact ThotKeeper
- CodeForces 593D Happy Tree Party
题目链接: http://codeforces.com/problemset/problem/593/D ----------------------------------------------- ...
- HBase–RegionServer宕机恢复原理
Region Server宕机总述 HBase一个很大的特色是扩展性极其友好,可以通过简单地加机器实现集群规模的线性扩展,而且机器的配置并不需要太好,通过大量廉价机器代替价格昂贵的高性能机器.但也正因 ...
- 实验报告(五)&第七周学习总结
实验目的 理解抽象类与接口的使用: 了解包的作用,掌握包的设计方法. 实验要求 掌握使用抽象类的方法. 掌握使用系统接口的技术和创建自定义接口的方法. 了解 Java 系统包的结构. 掌握创建自定义包 ...
- 搭建干净的Mac开发学习环境
docker + linux + gcc/g++ https://www.jianshu.com/p/d113db99fe24 https://www.jianshu.com/p/d26140d20c ...
- go 学习之gorm
gorm是一个饱受好评的orm框架,此处数据库我们以mysql为例 import ( "github.com/jinzhu/gorm" _ "github.com/jin ...