[CSP-S模拟测试41]题解
中间咕的几次考试就先咕着吧……
A.夜莺与玫瑰
枚举斜率。只考虑斜率为正且不平行于坐标轴的直线,最后把$ans\times 2$再$+1$即可。
首先肯定需要用$gcd(i,j)==1$确保斜率的唯一性,但由于题目中Deadline的定义是直线不是线段,所以一个方向只能有一条,需要去重。那么我们计算一条直线的贡献,当且仅当它和它的前驱线段在点阵内且后继线段不在点阵内。
暴力求解:$ans=\sum \limits_{i=1}^{n-1} \sum \limits_{j=1}^{m-1} [gcd(i,j)==1] ((n-i)\times(m-j)-\max (n-2i,0) \times \max (m-2j,0))$,时间复杂度$O(n^2 T)$。
尝试通过预处理降低每次询问的复杂度:计算对于每个$i$与它互质的$j$的前缀个数与前缀和,之后把柿子拆一下复杂度就变成$O(nT)$的了。
卡内存?值域不超过4000的数组为什么不用short呢?(滑稽
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int mod=(1<<30),N=4005;
typedef long long ll;
int n,m,T;
int sum[N][N];
short gcd[N][N],copr[N][N];
void work()
{
scanf("%d%d",&n,&m);
ll ans=0;
for(int i=1;i<=n-1;i++)
{
ll num1=1LL*(n-i)*(1LL*copr[i][m-1]*m-sum[i][m-1])%mod;
if(n-2*i>0)num1=(num1-1LL*(n-2*i)*(1LL*m*copr[i][m/2]-2*sum[i][m/2])+mod)%mod;
ans+=num1,ans%=mod;
} /*for(int i=1;i<=n-1;i++)
for(int j=1;j<=m-1;j++)
if(gcd(i,j)==1)ans+=(1LL*(n-i)*(m-j)-max(n-i*2,0LL)*max(m-j*2,0LL));*/
printf("%lld\n",(ans*2%mod+1LL*n+m)%mod);
} int main()
{
scanf("%d",&T);
gcd[1][1]=gcd[1][2]=gcd[2][1]=1;
for(int i=1;i<=4000;i++)
gcd[i][0]=i,gcd[i][1]=gcd[1][i]=1;
for(int i=1;i<=4000;i++)
{
for(int j=1;j<=4000;j++)
{
gcd[i][j]=gcd[min(i,j)][max(i,j)%min(i,j)];
copr[i][j]=copr[i][j-1],sum[i][j]=sum[i][j-1];
if(gcd[i][j]==1)copr[i][j]++,sum[i][j]+=j;
//if(i<=50&&j<=50)cout<<i<<' '<<j<<' '<<gcd[i][j]<<' '<<copr[i][j]<<' '<<sum[i][j]<<endl;
}
} while(T--)work();
return 0;
}
B.影子
树上的题居然还能并查集乱搞,学习了。
把所有的点按权值从大到小排序,然后扫一遍。对于每个点,尝试将它与和它相连且已经扫过的每个点合并。
并查集要维护当前集合中的最长链长度和最长链的两个端点。考虑合并时怎么处理两个集合的信息:新集合的最长链可能还是原来那两个集合中最长链的某一条,也有可能跨越了两个集合、由两个集合的最长链端点拼凑而来的。除此之外不会再有其它情况了。所以预处理一下到根的距离$dis[]$以及倍增lca,合并时枚举6种情况找到最优作为新集合的信息即可。
每个点合并完之后用当前点权$\times$当前点集最长链长度即可。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define pa pair<int,int>
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;
int T,n;
int tot,head[N],nxt[N<<1],to[N<<1],fa[N][25],dep[N],vis[N];
ll w[N],len[N<<1],dis[N];
pa p[N];
void add(int x,int y,ll z)
{
to[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
len[tot]=z;
}
void dfs(int x,int f)
{
fa[x][0]=f;
for(int i=1;i<=20;i++)
fa[x][i]=fa[fa[x][i-1]][i-1];
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==f)continue;
dep[y]=dep[x]+1;
dis[y]=dis[x]+len[i];
dfs(y,x);
}
}
int lca(int x,int y)
{
if(dep[x]>dep[y])swap(x,y);
for(int i=20;i>=0;i--)
if(dep[fa[y][i]]>=dep[x])y=fa[y][i];
if(x==y)return x;
for(int i=20;i>=0;i--)
if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
namespace U
{
int fa[N],node[N][3];
ll d[N];
void ini()
{
for(int i=1;i<=n;i++)
fa[i]=i,node[i][0]=i,node[i][1]=i,d[i]=0;
}
int findf(int x)
{
if(x==fa[x])return x;
return fa[x]=findf(fa[x]);
} void Merge(int x,int y)
{
int node1=node[x][0],node2=node[x][1];
ll maxd=d[x];
if(maxd<d[y])maxd=d[y],node1=node[y][0],node2=node[y][1]; for(int i=0;i<2;i++)
{
for(int j=0;j<2;j++)
{
int LCA=lca(node[x][i],node[y][j]);
ll nowd=dis[node[x][i]]+dis[node[y][j]]-dis[LCA]*2;
if(maxd<nowd)maxd=nowd,node1=node[x][i],node2=node[y][j];
}
}
d[x]=maxd;
node[x][0]=node1;node[x][1]=node2;
}
void merge(int x,int y)
{
int fx=findf(x),fy=findf(y);
if(fx!=fy)Merge(fx,fy),fa[fy]=fx;
}
}
void work()
{
n=read();
tot=0;
for(int i=1;i<=n;i++)
{
w[i]=head[i]=dep[i]=len[i]=dis[i]=vis[i]=0;
for(int j=0;j<=20;j++)
fa[i][j]=0;
}
U::ini();
for(int i=1;i<=n;i++)
w[i]=read(),p[i]=make_pair(-w[i],i);
for(int i=1;i<n;i++)
{
int x=read(),y=read();ll z=read();
add(x,y,z);add(y,x,z);
}
dep[1]=1;
dfs(1,0);
sort(p+1,p+n+1);ll ans=0;
for(int j=1;j<=n;j++)
{
int x=p[j].second;
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(vis[y])U::merge(x,y);
}
vis[x]=1;
ans=max(ans,U::d[x]*w[x]);
}
printf("%lld\n",ans);
return ;
}
int main()
{
T=read();
while(T--)work();
return 0;
}
C.玫瑰花精
$O(nm)$暴力有60分?什么辣鸡题
线段树。每个节点维护4个值:
$lp[]:$该节点维护区间内最左的花精的位置
$rp[]:$.....................................右.......................
$mi[]:$该节点维护区间内花精之间最长距离/2
$pos[]:$该节点维护区间内的答案(离得最远的两只花精的中间位置)
然后pushup()的时候分类讨论一下就行了。思想类似于山海经那道题,不过具体实现简单很多。
注意对于每个加入操作,要特殊考虑最左和最右端点是否空着。
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int N=2e5+5;
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;
}
int n,m,loc[1000005];
int lp[N<<2],rp[N<<2],pos[N<<2],mi[N<<2];
#define ls(k) (k)<<1
#define rs(k) (k)<<1|1
void up(int k)
{
lp[k]=lp[ls(k)]?lp[ls(k)]:lp[rs(k)];
rp[k]=rp[rs(k)]?rp[rs(k)]:rp[ls(k)];
mi[k]=mi[ls(k)];
pos[k]=pos[ls(k)];
if(!rp[ls(k)]||!lp[rs(k)])return ;
int val=(lp[rs(k)]-rp[ls(k)])>>1;
if(val>mi[k])mi[k]=val,pos[k]=(rp[ls(k)]+lp[rs(k)])>>1;
if(mi[rs(k)]>mi[k])mi[k]=mi[rs(k)],pos[k]=pos[rs(k)];
}
void update(int k,int l,int r,int Pos,int op)
{
if(l==r)
{
if(op==1)
{
lp[k]=l;rp[k]=r;
pos[k]=mi[k]=0;
}
else lp[k]=rp[k]=pos[k]=mi[k]=0;
return ;
}
int mid=l+r>>1;
if(Pos<=mid)update(ls(k),l,mid,Pos,op);
else update(rs(k),mid+1,r,Pos,op);
up(k);
} int main()
{
n=read();m=read();
while(m--)
{
int op=read(),x=read();
if(op==1)
{
if(!lp[1]){loc[x]=1;puts("1");update(1,1,n,1,1);continue;}
int maxx=-0x3f3f3f3f;
maxx=max(lp[1]-1,max(mi[1],n-rp[1]));
if(maxx==lp[1]-1)loc[x]=1;
else if(maxx==mi[1])loc[x]=pos[1];
else loc[x]=n;
printf("%d\n",loc[x]);
update(1,1,n,loc[x],1);
}
else update(1,1,n,loc[x],2);
}
return 0;
}
[CSP-S模拟测试41]题解的更多相关文章
- [考试反思]0909csp-s模拟测试41:反典
说在前面:我是反面典型!!!不要学我!!! 说在前面:向rank1某脸学习,不管是什么题都在考试反思后面稍微写一下题解. 这次是真的真的运气好... 这次知识点上还可以,但是答题策略出了问题... 幸 ...
- CSP-S 模拟测试94题解
T1 yuuustu: 可以对两边取对数,然后就转化为两个double的比较,时间复杂度$O(n)$ 然后我就用神奇0.4骗分水过 #include<bits/stdc++.h> usin ...
- CSP-S模拟测试 88 题解
T1 queue: 考场写出dp柿子后觉得很斜率优化,然后因为理解错了题觉得斜率优化完全不可做,只打了暴力. 实际上他是可以乱序的,所以直接sort,正确性比较显然,贪心可证,然后就是个sb斜率优化d ...
- CSP-S 模拟测试92 题解
话说我怎么觉得我没咕多长时间啊,怎么就又落了20多场题解啊 T1 array: 根据题意不难列出二元一次方程,于是可以用exgcd求解,然而还有一个限制条件就是$abs(x)+abs(y)$最小,这好 ...
- CSP-S 模拟测试57题解
人生第一次A,B层一块考rank2,虽然说分差没几分,但还是值得纪念. 题解: T1 天空龙: 大神题,因为我从不写快读也没有写考场注释的习惯,所以不会做,全hzoi就kx会做,kx真大神级人物. T ...
- CSP-S 模拟测试 51 题解
考试过程: 惯例先看一遍三道题,T1 一开始反应要求割点,但是这是有向图,肯定不能求割点,康了一下数据范围,有40%是树的,还不错,决定待会在打. 看T2 字符串题,完了我字符串最弱了,肯定只能打暴力 ...
- CSP-S 模拟测试 45 题解
由于咕掉的题解太多了,所以只能趁改完不动题的时间,来补补坑qwq,还是太弱了. 考试过程: 到新机房的第一次考试,貌似海星? 第一题一开始就觉得是个贪心,但以为所有小怪兽都要打完,所以想复杂了,但后来 ...
- [CSP-S模拟测试97]题解
A.小盆友的游戏 感觉题解解释的很牵强啊……还是打表找规律比较靠谱 对于每个人,它构造了一个期望函数$f(x)$,设它的跟班个数为$cnt[x]$,那么令$f(x)=2^{cnt[x]}-1$(??鬼 ...
- [CSP-S模拟测试96]题解
以后不能再借没改完题的理由不写题解了…… A.求和 求$\sum \sum i+j-1$ 柿子就不化了吧……这年头pj都不考这么弱智的公式化简了…… 坑点1:模数不定,可能没有2的逆元,那么只要先把乘 ...
随机推荐
- View使用总结
1. View的基础知识 View的位置参数 —— 相对于父容器的位置 view在平移时,top和left表示的是原始左上角位置信息,值不会改变, 改变的是x,y(View左上角坐标),transla ...
- nIce 不看会后悔的o!
今天小编来跟大家探讨关于“控件”.控件非常好玩,可以构建出不同的场景和不同风格的Windows画面.相信大家绝对狠感兴趣是吧~~~ 好了,下面小编就为大家来展示风采喽 下面先为大家展示一些比较基础 ...
- DZY Loves Math
DZY Loves Math 对于正整数 $n$,定义 $f(n)$ 为 $n$ 所含质因子的最大幂指数. 例如 $f(1960)=f(2^3 * 5^1 * 7^2)=3, f(10007)=1, ...
- [CSP-S模拟测试]:attack(支配树+LCA+bitset)
题目传送门(内部题55) 输入格式 第一行,包含两个整数:$n,m,q$,表示敌军城市数.路数和情报数.接下来$m$行,每行包含两个整数:$u,v$,表示从$u$到$v$包含一条单向道路.接下来$q$ ...
- windows汇编语言开发环境搭建
1.下载软件mash32 http://www.masm32.com/download/masm32v11r.zip 此软件包含对汇编文件的编译和运行,下载后直接运行并解压即可 2.配置环境变量 在系 ...
- vue 页面添加水印 ts
"use strict"; // tslint:disable-next-line: only-arrow-functions const setWatermark: (str: ...
- Flink容错机制(checkpoint)
checkpoint是Flink容错的核心机制.它可以定期地将各个Operator处理的数据进行快照存储( Snapshot ).如果Flink程序出现宕机,可以重新从这些快照中恢复数据. 1. ch ...
- oo_project_1
Project 1题目要求分析: 实现多项式的加减运算,主要问题是解决输入格式的判断问题. 输入实例: {(3,0), (2,2), (12,3)} + {(3,1), (-5,3)} – {(-19 ...
- List集合--Vector子类
Vector子类 Vector是一个原始古老的程序类,这个类是在JDK1.0的时候就提供的,而后到了JDK1.2的时候,由于有一部分开发者已经习惯于使用Vector,并且许多的系统类也是基于Vecto ...
- HDU 1387 Team Queue( 单向链表 )
Team Queue Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total ...