2019.10.30 csp-s模拟测试94 反思总结

头一次做图巨的模拟题OWO

自从上一次听图巨讲课然后骗了小礼物以后一直对图巨印象挺好的233

T1:

对于XY取对数=Y*log(x)

对于Y!取对数=log(1*2*3*...*Y)=log1+log2+log3+...+logY

因为数字大小不超过1e5,直接累加最后比较就可以了

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int t,x,y;
double a,b;
int main()
{
    freopen("yuuutsu.in","r",stdin);
    freopen("yuuutsu.out","w",stdout);
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&x,&y);
        a=y*log(x);
        b=0;
        for(int i=1;i<=y;i++){
            b+=log(i);
        }
        if(a<=b)printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}

T2:

每一次操作会让区间整体加或减->在差分数组上首位加减

列出目标序列的差分数组,可以进行操作让一个位置的数字移动k步,如果有大小相同的数字撞在一起就会消掉,不同的话可以合并。想起星空这道题,不同的是今天的T2只能走k一种步数且差分值并不只代表一种状态

目标是要让所有的值变成0,又想到一道跳斑马线的题……?考虑把位置对于k取模余数不同的数字分开处理。维护位置对于k取模后余数为下标,记录差分值之和的m数组。用树状数组维护当前的m是否都为0。

#include<iostream>
#include<cstdio>
using namespace std;
const int N=2e6+10;
int n,k,q,a[N],sum[N],m[N];
long long tree[N];
void add(int x,int y){
    for(;x<=k;x+=(x&-x))tree[x]+=y;
}
long long ask(int x){
    long long num=0;
    for(;x;x-=(x&-x))num+=tree[x];
    return num;
}
int main()
{
    freopen("august.in","r",stdin);
    freopen("august.out","w",stdout);
    scanf("%d%d%d",&n,&k,&q);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        m[i%k]+=a[i]-a[i-1];
    }
    m[(n+1)%k]+=-a[n];
    for(int i=0;i<k;i++){
        add(i+1,(m[i]!=0));
    }
    if(!ask(k))printf("Yes\n");
    else printf("No\n");
    for(int i=1,x,pos;i<=q;i++){
        scanf("%d%d",&pos,&x);
        int pos0=pos%k,pos1=(pos+1)%k;
        int val=(m[pos0]!=0),val1=(m[pos1]!=0);
        m[pos0]=m[pos0]-a[pos]+a[pos-1];
        m[pos1]=m[pos1]-a[pos+1]+a[pos];
        a[pos]+=x;
        m[pos0]=m[pos0]+a[pos]-a[pos-1];
        m[pos1]=m[pos1]+a[pos+1]-a[pos];
        add(pos0+1,(m[pos0]!=0)-val);
        add(pos1+1,(m[pos1]!=0)-val1);
        if(!ask(k))printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}

发现自己对于m是否都为0的处理过于麻烦了…这是何种山路十八弯的脑回路才会想到这种处理…

其实是中途思路锅了,保留了树状数组的写法XD其实直接记一个m不为0的数量,每次m变化的时候进行更新就好了

T3:

将问题转化成,对于树上的一个点,会对多少区间产生贡献。

线段树维护子树中存在哪些位置的点,线段树下标是在a数组中的位置。如果这个点可以对一段区间产生贡献,那么这段区间在线段树种一定是连续的1,中间若存在0则代表这段区间中在更高的地方存在点。在线段树上统计答案,记录线段树每个节点从左端点开始最长的一段1的长度lonl,从右端点开始最长的一段1的长度lonr,以及包含的区间个数val。val=左儿子的val+右儿子的val+左儿子lonr*右儿子lonl(端点在两边的区间数量)。这样计算一定不重不漏,有线段树分治的意味。

维护节点x的线段树的时候,对所有儿子进行线段树合并,再把x点insert进去。注意当前节点线段树root的区间个数要减去节点儿子们的区间个数,才能用来累计答案。

#include<iostream>
#include<cstdio>
using namespace std;
const int N=2000010;
int n,tot,cnt;
int ver[N],Next[N],head[N];
int a[N],b[N],pos[N],T[N],L[N*22],R[N*22],lonl[N*22],lonr[N*22];
long long ans,sum[N],val[N*22];
void add(int x,int y){
    ver[++tot]=y;
    Next[tot]=head[x];
    head[x]=tot;
}
void update(int p,int l,int r){
    int mid=(l+r)/2;
    if(lonl[L[p]]==mid-l+1)lonl[p]=mid-l+1+lonl[R[p]];
    else lonl[p]=lonl[L[p]];
    if(lonr[R[p]]==r-mid)lonr[p]=r-mid+lonr[L[p]];
    else lonr[p]=lonr[R[p]];
    val[p]=val[L[p]]+val[R[p]]+1ll*lonr[L[p]]*lonl[R[p]];
}
void change(int &p,int p0,int l,int r){
    if(!p){
        p=p0;
        return;
    }
    int mid=(l+r)/2;
    if(L[p0])change(L[p],L[p0],l,mid);
    if(R[p0])change(R[p],R[p0],mid+1,r);
    update(p,l,r);
}
void ins(int &p,int l,int r,int pos){
    if(!p)p=++cnt;
    if(l==r){
        lonl[p]=lonr[p]=1;
        val[p]=0;
        return;
    }
    int mid=(l+r)/2;
    if(pos<=mid)ins(L[p],l,mid,pos);
    else ins(R[p],mid+1,r,pos);
    update(p,l,r);
}
void dfs(int x){
    for(int i=head[x];i;i=Next[i]){
        int y=ver[i];
        dfs(y);
        sum[x]+=sum[y];
        change(T[x],T[y],1,n);
    }
    ins(T[x],1,n,pos[x]);
    long long num=val[T[x]];
    ans+=(num-sum[x])*b[x];
    sum[x]=num;
}
int main()
{
    freopen("sagittarius.in","r",stdin);
    freopen("sagittarius.out","w",stdout);
    scanf("%d",&n);
    for(int i=2,x;i<=n;i++){
        scanf("%d",&x);
        add(x,i);
//        st[i][0]=x;
    }
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),pos[a[i]]=i;
    for(int i=1;i<=n;i++)scanf("%d",&b[i]),ans+=b[i];
    dfs(1);
    printf("%lld\n",ans);
    return 0;

}

原文地址:https://www.cnblogs.com/chloris/p/11768151.html

时间: 2024-11-05 21:53:40

2019.10.30 csp-s模拟测试94 反思总结的相关文章

csp-s模拟测试94

csp-s模拟测试94 一场简单题,打爆了.$T1$脑抽分解质因数准备分子分母消,想了半天发现$jb$互质直接上天,果断码了高精滚蛋.$T2$无脑手玩大样例,突然灵光一闪想到映射到前$K$大小的区间,$T3$写完暴力准备划水,突然发现特殊性质可写,$10$分钟拯救了$25$分. 80 03:24:46 70 03:24:58 65 03:25:10 215 03:25:10 没办法就是菜,退役也不暝目. A. 凉宫春日的忧郁 转成对数轻松过. B. 漫无止境的八月 取模到$K$大小的区间,$ha

2019/10/17 CSP模拟 总结

T1 补票 Ticket 没什么好说的,不讲了 T2 删数字 Number 很后悔的是其实考场上不仅想出了正解的方程,甚至连优化都想到了,却因为码力不足只打了\(O(n^2)\)暴力,甚至还因为细节挂成了\(40\ pts\) 以后还是应该多写一下码农题 规定一下,下面的\(j\)没有特殊说明,取值范围默认在\(1, i - 1\) 考虑什么情况是合法的,首先最后对答案有贡献的元素组成的序列一定是严格上升的,即\(a_i > a_j\) 然后考虑还有没有别的限制呢 放一个图 看到我们的对答案有贡

2019.10.21 csp-s模拟测试81 反思总结

T1: 把每一行状压,按行DP.设fi,j,k,i表示第几行,j是当前行的1覆盖状态,k是当前行选择按钮的状态.转移的时候枚举j和k,再枚举下一层的按钮选择情况l.如果l和j可以全覆盖当前层则转移合法,根据下一层选择l状态的代价进行转移.预处理一行每一种选法i可以覆盖到的状态di,各行选择按钮状态i对应的代价dpi,以及每一行的初始状态bi.转移时下一层的覆盖情况就是k|dl|bi+1.初始化第一层是所有选法i对应的代价,即f1,d[i]|b[1],i=dp1,i. 整个DP过程的复杂度是O(3

2019.10.22 csp-s模拟测试82 反思总结

算了 我在干什么orz T2: #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=1e5+10,p=1500007,mod=998244353; int n,len,cnt1=1,cnt2=1,lens; char s[2*N],c[2*N]; int tree1[2*N][27],tree2[2*N][27]; unsigned long lon

2019.10.26 csp-s模拟测试88 反思总结

今天的主人公是什么? 60.1K!!!! 先扔代码再更新防止我等会儿一上头不打算写完题解 T1: #include<iostream> #include<cstdio> #include<algorithm> using namespace std; const double inf=214748364; int n,k; double a[100010],f[21][100010]; int main() { scanf("%d%d",&n

2019.10.26 CSP%您赛第三场

\(CSP\)凉心模拟^_^ --题源\(lqx.lhc\)等各位蒟蒻 题目名称 比赛 传递消息 开关灯 源文件名 \(competition.cpp\) \(message.cpp\) \(light.cpp\) 输入文件名 \(competition.in\) \(message.in\) \(light.in\) 输出文件名 \(competition.out\) \(message.out\) \(light.out\) 测试点时限 \(1s\) \(1s\) \(2s\) 内存限制 \

18.10.30绍一模拟赛

T1斐波那契 题意 给定一个长度为n的数列,第i个数为\(a_i\),要求给数列划分. 要求一个块内任意两个数之和不在斐波那契数列上. [样例输入] 5 1 5 2 6 1 5 2 6 7 [样例输出] 4 [样例说明] 最优分组的一种为: 最优分组的一种为: 最优分组的一种为: 最优分组的一种为: 最优分组的一种为: 最优分组的一种为: {1}, {5, 2}, {6}, {7}. [数据范围] 对于 10% 的数据,\(n ≤ 20\). 对于 30% 的数据,\(n ≤ 300\). 对于

2019.9.28 csp-s模拟测试54 反思总结

咕咕咕的冲动如此强烈x T1x: 看完题目想了想,感觉把gcd不为1的强行放在一组,看作一个连通块,最后考虑连通块之间的组合方式就可以了. 然后维护这个连通块可以写并查集可以连边跑dfs怎么着都行… 然而我在处理数字分解质因数这里T掉了,原因是一个很显然的优化写法我基本没怎么写过.线性筛的时候记录每个数是被哪个质数标记过的,分解一个数的时候直接处理记录下来的质数就可以. #include<iostream> #include<cstdio> #include<cmath>

【2019.10.25 OI-Killer的模拟赛】3.鸡数

题目链接 题意: 定义“鸡数”指从高位到低位单调不减的数.求$[a,b]$之间有多少个“鸡数”.$t$组询问. $1\le t\le 10^5,\; 1\le a\le b\le 2^{31}-1$ 分析: 数位DP.设$f[i][j]$表示长度为$i$,最高位是$j$的“鸡数”个数,那么$$f[i][j]=\sum\limits^9_{k=j}f[i-1][k]$$ 且$$f[1][i]=1\;(1\le i\le 9)$$ 那么对于一个长度为$l$的$n$且由低到高位写成$s_{1\dots