Educational Codeforces Round 81 做题记录

A.

奇数个就第一位放7,后面放1;偶数个就全放1

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int T,n;
 4 int main()
 5 {
 6     scanf("%d",&T);
 7     while(T--)
 8     {
 9         scanf("%d",&n);
10         if(n&1)
11         {
12             printf("7");
13             for(int i=1;i<n/2;++i)printf("1");
14         }
15         else
16         {
17             for(int i=1;i<=n/2;++i)printf("1");
18         }
19         puts("");
20     }
21 }
View Code

B.

先判断x是否为0,为0则在0处有一个

判断走一轮之后的d:

\(d=0\),则balance值不变,如果有一个等于的就是无穷,否则为0

\(d>0\),则balance上升,判一下模意义下是否相同以及是否通过上升可以得到即可

\(d<0\)同理

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int T,n,x;
 4 char s[100005];
 5 int a[100005];
 6 int main()
 7 {
 8     scanf("%d",&T);
 9     while(T--)
10     {
11         scanf("%d%d",&n,&x);
12         scanf("%s",s+1);
13         for(int i=1;i<=n;++i)if(s[i]=='0')a[i]=a[i-1]+1;else a[i]=a[i-1]-1;
14         int d=a[n];
15         if(d==0)
16         {
17             bool yes=0;
18             for(int i=1;i<=n;++i)if(a[i]==x)yes=1;
19             if(yes)puts("-1");
20             else
21             {
22                 if(x==0)puts("1");
23                 else puts("0");
24             }
25         }
26         else
27         {
28             int ans=0;
29             if(x==0)ans++;
30             for(int i=1;i<=n;++i)
31             {
32                 if(d>0&&x>=a[i]&&(x%d+d)%d==(a[i]%d+d)%d)ans++;
33                 if(d<0&&x<=a[i]&&(x%d+d)%d==(a[i]%d+d)%d)ans++;
34             }
35             printf("%d\n",ans); 
36         }
37     }
38 }
View Code

C.

贪心,建个子序列自动机加速一下就完事

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int T;
 4 char s[100005],t[100005];
 5 int nxt[100005][26];
 6 int main()
 7 {
 8     scanf("%d",&T);
 9     while(T--)
10     {
11         scanf("%s",s+1);
12         scanf("%s",t+1);
13         int n=strlen(s+1),m=strlen(t+1);
14         for(int j=0;j<26;++j)nxt[n][j]=0;
15         for(int i=n-1;i>=0;--i)
16         {
17             for(int j=0;j<26;++j)nxt[i][j]=nxt[i+1][j];
18             nxt[i][s[i+1]-'a']=i+1;
19         }
20         int now=0,ans=1;
21         for(int i=1;i<=m;++i)
22         {
23             now=nxt[now][t[i]-'a'];
24             if(!now)
25             {
26                 ans++;
27                 now=nxt[now][t[i]-'a'];
28                 if(!now){ans=-1;break;}
29             }
30         }
31         printf("%d\n",ans);
32     }
33 }
View Code

D.

实际上可以通过gcd的性质得到答案就是\(gcd(x,m/gcd(a,m))=1\)的x个数,求个phi就没了

傻逼选手不会这性质就写了个容斥。。。但是好像可以推广到没有\(0 \leq x < m\)条件的情况

令\(p=gcd(a,m),x=kp,a=tp,m=bp\)

则\(x+a=(k+t)p\)

就是求\([0,\frac{m-1}{p}]\)中满足\(gcd(k+t,b)=1\)的k的个数

然后可以差分转化成\(0 \leq k \leq n\)中满足\(gcd(k,b)=1\)的\(k\)的个数

然后考虑容斥

枚举\(b\)的因数\(p_i\),则\(Ans=\sum{\mu(p_i)*\frac{n}{p_i}}\)

这里的\(mu(p_i)\)可以通过一些方法快速计算:

考虑\(p_i\)为\(b\)的约数,那么我们预处理出来\(b\)的所有质因子,然后判断每个质因子在\(p_i\)中出现了一次还是出现了多次,若出现多次则\(mu=0\),否则按定义计算

然后这样单次求mu就是\(O(\log n)\)的

复杂度\(O(T\sqrt{n} \log n)\)

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 int T;
 5 ll a,m;
 6 ll gcd(ll a,ll b)
 7 {
 8     if(!b)return a;
 9     return gcd(b,a%b);
10 }
11 ll mu(ll x,vector<ll> A)
12 {
13     ll res=1;
14     for(ll p:A)if(x%p==0)
15     {
16         ll t=0;
17         while(x%p==0)
18         {
19             t++,x/=p;
20             if(t>1)break;
21         }
22         if(t>1)
23         {
24             res=0;break;
25         }
26         else res*=-1;
27     }
28     return res;
29 }
30 ll solve(ll n,ll b)
31 {
32     vector<ll> A;
33     A.clear();
34     ll x=b;
35     for(ll i=2;i*i<=b;++i)if(x%i==0)
36     {
37         while(x%i==0)x/=i;
38         A.push_back(i);
39     }
40     if(x>1)A.push_back(x);
41     ll res=0;
42     for(ll i=1;i*i<=b;++i)if(b%i==0)
43     {
44         res+=mu(i,A)*(n/i);
45         if(i*i!=b)res+=mu(b/i,A)*(n/(b/i));
46     }
47     return res;
48 }
49 int main()
50 {
51     cin>>T;
52     while(T--)
53     {
54         cin>>a>>m;
55         ll p=gcd(a,m);
56         ll t=a/p,b=m/p;
57         ll ans=solve((m-1)/p+t,b)-solve(t-1,b);
58         cout<<ans<<endl;
59     }
60 }
View Code

E.

考虑用线段树维护最后分界点在每一个位置的答案

然后枚举初始划分位置从1到n-1

每次移动划分位置对应一段区间加和一段区间减

每次和全局最小取min即可

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 int n,p[200005],a[200005],id[200005];
 5 ll minv[800005],val[200005],addv[800005];
 6 void pushup(int rt)
 7 {
 8     minv[rt]=min(minv[rt<<1],minv[rt<<1|1]);
 9 }
10 void pushdown(int rt)
11 {
12     if(addv[rt])
13     {
14         ll t=addv[rt];
15         minv[rt<<1]+=t;minv[rt<<1|1]+=t;
16         addv[rt<<1]+=t;addv[rt<<1|1]+=t;
17         addv[rt]=0;
18     }
19 }
20 void build(int rt,int l,int r)
21 {
22     int mid=(l+r)>>1;
23     if(l==r){minv[rt]=val[l];return;}
24     build(rt<<1,l,mid);build(rt<<1|1,mid+1,r);
25     pushup(rt);
26 }
27 void add(int rt,int l,int r,int ql,int qr,ll v)
28 {
29     int mid=(l+r)>>1;
30     if(ql<=l&&r<=qr)
31     {
32         addv[rt]+=v;minv[rt]+=v;
33         return;
34     }
35     pushdown(rt);
36     if(ql<=mid)add(rt<<1,l,mid,ql,qr,v);
37     if(qr>mid)add(rt<<1|1,mid+1,r,ql,qr,v);
38     pushup(rt);
39 }
40 int main()
41 {
42     scanf("%d",&n);
43     for(int i=1;i<=n;++i)scanf("%d",&p[i]),id[p[i]]=i;
44     for(int i=1;i<=n;++i)scanf("%d",&a[i]);
45     for(int i=1;i<=n;++i)val[i]=val[i-1]+a[id[i]];
46     build(1,0,n);
47     ll ans=(ll)1e18;
48     for(int i=1;i<n;++i)
49     {
50         add(1,0,n,0,p[i]-1,a[i]);
51         add(1,0,n,p[i],n,-a[i]);
52         ans=min(ans,minv[1]);
53     }
54     cout<<ans<<endl;
55 }
View Code

 

posted @ 2020-01-30 01:52  幽蝶  阅读(259)  评论(0编辑  收藏  举报