CSP-S 模拟测试94题解

T1 yuuustu:

可以对两边取对数,然后就转化为两个double的比较,时间复杂度$O(n)$

然后我就用神奇0.4骗分水过

 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=1e6+10;
 4 struct BigInt{
 5     int a[100005];
 6     BigInt(){memset(a,0,sizeof(a));a[0]=a[1]=1;}
 7     BigInt friend operator * (BigInt x,int y){
 8         int len=x.a[0],las=0;
 9         for(register int i=1;i<=len;++i){
10             x.a[i]=x.a[i]*y+las;
11             las=x.a[i]/10;
12             x.a[i]%=10;
13             if(i==len&&las) ++len;
14         }
15         return x.a[0]=len,x;
16     }
17     void print(){
18         for(int i=a[0];i>=1;--i) cout<<a[i];
19     }
20 };
21 inline bool chk(BigInt a,BigInt b){
22     for(int i=0;i<=a.a[0];++i) if(a.a[i]!=b.a[i]) return 0;
23     return 1;
24 }
25 inline bool cmp(BigInt a,BigInt b){//x^y   y!
26     if(a.a[0]==b.a[0]) if(chk(a,b)) return 1;
27     if(a.a[0]^b.a[0]) return a.a[0]<b.a[0];
28     else{
29         for(register int i=a.a[0];i>=1;--i){
30             if(a.a[i]==b.a[i]) continue;
31             if(a.a[i]>b.a[i]) return 0;
32             else if(a.a[i]<b.a[i]) return 1;
33         }
34     }
35 }
36 void work_1(int x,int y){
37     if(x>y*0.4) puts("No");
38     else puts("Yes");
39 }
40 int main(){
41     freopen("yuuutsu.in","r",stdin);
42     freopen("yuuutsu.out","w",stdout);
43     int T;
44     scanf("%d",&T);register int x,y;
45     while(T--){
46         scanf("%d%d",&x,&y);
47         if(x>1000||y>1000){work_1(x,y);continue;}
48         BigInt Fir,Sec;
49         Fir.a[0]=Fir.a[1]=1;
50         Sec.a[0]=Sec.a[1]=1;
51         for(register int i=1;i<=y;++i) Fir=Fir*x;
52         for(register int i=1;i<=y;++i) Sec=Sec*i;
53         //Fir.print();puts("");Sec.print();
54         if(cmp(Fir,Sec)) puts("Yes");
55         else puts("No");
56     }
57     fclose(stdin);
58     fclose(stdout);
59     return 0;
60 }
yuuutsu

 

T2 august:

先考虑暴力,我们一个一个考虑每个位置,暴力每个位置置为零,当到最后k个时,看一下是否都为零,如果是Yes,否则No。

考虑优化这个过程因为是个区间修改,所以考虑差分,我们维护一个差分数组,发现只有在模k相等的位置才会互相影响,所以维护一个sum数组,含义为模k为i的下标的差分数组之和,这样只要看他是否全为0即可。每次修改只需维护一个桶,每次修改两个位置就好。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=2e6+10;
 4 int a[N],tong[N];
 5 int main(){
 6     freopen("august.in","r",stdin);
 7     freopen("august.out","w",stdout);
 8     int n,k,q,cnt=0;
 9     scanf("%d%d%d",&n,&k,&q);
10     for(int i=1;i<=n;++i) scanf("%d",&a[i]);
11     for(int i=1;i<=n+1;++i) tong[i%k]+=(a[i]-a[i-1]);
12     for(int i=0;i<k;++i) if(tong[i]) cnt++;
13     if(cnt) puts("No");
14     else puts("Yes");
15     for(int i=1;i<=q;++i){
16         int pos,w;
17         scanf("%d%d",&pos,&w);
18         if(tong[pos%k]){
19             tong[pos%k]+=w;
20             if(!tong[pos%k]) cnt--;
21         }
22         else{
23             tong[pos%k]+=w;
24             if(tong[pos%k]) cnt++;
25         }
26         ++pos,w*=-1;
27         if(tong[pos%k]){
28             tong[pos%k]+=w;
29             if(!tong[pos%k]) cnt--;
30         }
31         else{
32             tong[pos%k]+=w;
33             if(tong[pos%k]) cnt++;
34         }
35         if(cnt) puts("No");
36         else puts("Yes");
37     }
38 }
august

T3 sagittarius:

考场上一直想如何去掉非LCA的祖先的贡献,没有想出来,看了题解后发现是非常巧妙的差分处理,即我们设出一个新权值$wt[x]=val[x]-val[fa[x]]$,这样就避免了重复贡献,再用新权值乘以他的子树中所有连续区间即可,发现这个东西暴力统计是布星的,所以我们考虑用线段树合并维护每一个区间(这里所说的区间是子树)从左端点开始的最长连续区间,从右端点开始的最长连续区间和区间内的连续子区间数,则$sn[x]=sn[ls[x]]+sn[rs[x]]+rm[ls[x]]*lm[rs[x]]$,$lm$和$rm$的维护分类讨论即可。

 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=2e5+10,M=N*50;
 4 #define int long long
 5 int first[N],nex[N<<1],to[N<<1],tot;
 6 int fa[N],d[N],val[N],rk[N],ans,n,a[N],wt[N];
 7 int root[M],lm[M],rm[M],sn[M],ls[M],rs[M];
 8 void add(int a,int b){
 9     to[++tot]=b,nex[tot]=first[a],first[a]=tot;
10 }
11 void update(int p,int l,int r){
12     
13     int mid=l+r>>1;
14     if(lm[ls[p]]==mid-l+1) lm[p]=lm[ls[p]]+lm[rs[p]];
15     else lm[p]=lm[ls[p]];
16     if(rm[rs[p]]==r-mid) rm[p]=rm[rs[p]]+rm[ls[p]];
17     else rm[p]=rm[rs[p]];
18     sn[p]=sn[ls[p]]+sn[rs[p]]+lm[rs[p]]*rm[ls[p]];
19 }
20 int merge(int x,int y,int l,int r){
21     if(!x||!y) return x|y;
22     int mid=(l+r)>>1;
23     ls[x]=merge(ls[x],ls[y],l,mid);
24     rs[x]=merge(rs[x],rs[y],mid+1,r);
25     update(x,l,r);
26     return x;
27 }
28 int cnt=0;
29 void insert(int &x,int l,int r,int pos){
30     if(!x) x=++cnt;
31     if(l==r) return lm[x]=1,rm[x]=1,sn[x]=1,void();
32     int mid=(l+r)>>1;
33     if(pos<=mid) insert(ls[x],l,mid,pos);
34     else insert(rs[x],mid+1,r,pos);
35     update(x,l,r);
36 }
37 void dfs(int x){
38     insert(root[x],1,n,rk[x]);
39     wt[x]=val[x]-val[fa[x]];
40     for(int i=first[x];i;i=nex[i]){
41         int y=to[i];
42         if(y==fa[x]) continue;
43         dfs(y);
44         root[x]=merge(root[x],root[y],1,n);
45     }
46     ans+=wt[x]*sn[root[x]];
47     //cout<<"x=="/*<<x<<" ans=="*/<<sn[root[x]]<<endl;
48 }
49 signed main(){
50     freopen("sagittarius.in","r",stdin);
51     freopen("sagittarius.out","w",stdout);
52     scanf("%lld",&n);
53     for(int i=2;i<=n;++i) {
54         scanf("%lld",&fa[i]);
55         add(fa[i],i);
56         add(i,fa[i]);
57     }
58     //for(int i=1;i<=n;++i) cout<<fa[i]<<" ";cout<<endl;
59     for(int i=1;i<=n;++i) scanf("%lld",&a[i]),rk[a[i]]=i;
60     //for(int i=1;i<=n;++i) cout<<rk[i]<<" ";cout<<endl;
61     for(int i=1;i<=n;++i) scanf("%lld",&val[i]);
62     dfs(1);
63     printf("%lld\n",ans);
64 }
sagittarius

 

posted @ 2019-11-01 09:49  Barça_10  阅读(178)  评论(0编辑  收藏  举报