这次比赛又加了18分,加油,上(ao)紫(li)名(gei)!
虽然过程有点困难,让我很不痛快,中间小失误太多,竟然只排到了600+。
这次的第五题较水(相对而言),但是线段树太烦了,等我想好怎么做只剩20分钟了,20分钟写线段树?
其实主要是我自己对线段树不太熟悉,每次写都会遇到一些莫名其妙的问题,看来提前准备代码还是有些必要的。
比赛是这个:
https://codeforces.com/contest/1295
我说过一句话“前三题太水就不讲了”,现在我改为“没有水题太坑了!”
第一题:
贪心如果棒子数量是奇数,那么输出一个 最高位是7,后面都是1 的数;否则输出一个全是1的数。
(然而这题我WA了一次)
代码:

1 #pragma GCC optimize(3)
2 #include<bits/stdc++.h>
3 #define ll long long
4 #define F first
5 #define S second
6 #define P pair
7 #define FOR(i,a,b) for(int i=a;i<=b;i++)
8 #define V vector
9 #define RE return
10 #define ALL(a) a.begin(),a.end()
11 #define MP make_pair
12 #define PB push_back
13 #define PF push_front
14 #define FILL(a,b) memset(a,b,sizeof(a))
15 using namespace std;
16 void solve(){
17 int n;
18 cin>>n;
19 if(n&1){
20 cout<<'7';
21 for(int i=1;i<n/2;i++)cout<<'1';
22 cout<<"\n";
23 }else {
24 for(int i=1;i<=n/2;i++)cout<<'1';
25 cout<<'\n';
26 }
27 }
28 int main(){
29 ios::sync_with_stdio(0);
30 cin.tie(0);
31 int t;
32 cin>>t;
33 while(t--)solve();
34 RE 0;
35 }
第二题:
这是第一次我第一题做完还没有人做出来第二题。
我花了39min,太坑了!!!!!(此处省略无数‘!'
先统计s中0,1的个数,如果相等,那么特殊处理一下:如果单凭一个s就能产生答案,那么输出-1,否则输出0.
可以发现如果0,1个数不相等,那么s中每个位置都只可能在答案最后一个不完整的s中出现一次。
可以枚举t以s的哪一个位置结尾,再判断是否可以通过在前面加上s,使它成立。
最后输出得到的答案。
上代码(这道题气得我怒砸键盘):

1 #pragma GCC optimize(3)
2 #include<bits/stdc++.h>
3 #define ll long long
4 #define F first
5 #define S second
6 #define P pair
7 #define FOR(i,a,b) for(int i=a;i<=b;i++)
8 #define V vector
9 #define RE return
10 #define ALL(a) a.begin(),a.end()
11 #define MP make_pair
12 #define PB push_back
13 #define PF push_front
14 #define FILL(a,b) memset(a,b,sizeof(a))
15 using namespace std;
16 string s;
17 bool check(int x1,int x2,int x3){
18 x3-=x1;
19 if(x3<0&&x2>0||x3>0&&x2<0)RE 0;
20 RE x3%x2==0;
21 }
22 void solve(){
23 int n,m;
24 cin>>n>>m;
25 cin>>s;
26 int t1,t0;
27 t1=t0=0;
28 for(int i=0;i<s.size();i++){
29 if(s[i]=='1')t1++;else t0++;
30 }
31 if(t1==t0){
32 int q1=0,q0=0;
33 for(int i=0;i<s.size();i++){
34 if(q0-q1==m){
35 cout<<"-1\n";RE;
36 }
37 if(s[i]=='1')q1++;else q0++;
38 }
39 cout<<"0\n";RE;
40 }
41 int q1=0,q0=0,ans=0;
42 for(int i=0;i<s.size();i++){
43 if(check(q0-q1,t0-t1,m)){
44 ans++;
45 }
46 if(s[i]=='1')q1++;else q0++;
47 }
48 cout<<ans<<'\n';
49 }
50 int main(){
51 ios::sync_with_stdio(0);
52 cin.tie(0);
53 int t;
54 cin>>t;
55 while(t--)solve();
56 RE 0;
57 }
第三题:
这道题我T了一次,WA了一次。
太惨了。。。
可以把每个字母分开处理(这样二分时可以保证单调性),每次记录上个字符是在哪找到的,从它后面找第一个和现在字符一样的字符。
如找不到,那么新开一个字符串,重头开始找,还找不到,输出-1.
每次新开字符串时记录一下,就可以得出答案。
上代码:

1 #pragma GCC optimize(2)
2 #include<bits/stdc++.h>
3 #define ll long long
4 #define F first
5 #define S second
6 #define P pair
7 #define FOR(i,a,b) for(int i=a;i<=b;i++)
8 #define V vector
9 #define RE return
10 #define ALL(a) a.begin(),a.end()
11 #define MP make_pair
12 #define PB push_back
13 #define PF push_front
14 #define FILL(a,b) memset(a,b,sizeof(a))
15 using namespace std;
16 V<int> v[30];
17 void solve(){
18 FOR(i,1,26)v[i].clear();
19 string s,t;
20 cin>>s>>t;
21 for(int i=0;i<s.size();i++)v[s[i]-'a'+1].PB(i);
22 int l=0,f,ans=1;
23 V<int>::iterator iter;
24 for(int i=0;i<t.size();i++){
25 f=t[i]-'a'+1;
26 if(!v[f].size()){
27 cout<<"-1\n";RE ;
28 }
29 iter=lower_bound(ALL(v[f]),l);
30 if(iter==v[f].end()){
31 l=v[f][0]+1;ans++;
32 }else{
33 l=(*iter)+1;
34 }
35 }
36 cout<<ans<<'\n';
37 }
38 int main(){
39 ios::sync_with_stdio(0);
40 cin.tie(0);
41 int t;
42 cin>>t;
43 while(t--)solve();
44 RE 0;
45 }
第四题:
还好第四题我13分钟就对了,要不然我就死定了。
先令t=gcd(a,m),让a和m去除以t,因为合法的x也只可能是t的倍数。
先让答案等于m个,再求出m的质因数,用概率论从答案中去掉不合法的,最后得出答案(这句话貌似成了我的口头禅)。
注意要算上0.
上代码:

1 #pragma GCC optimize(3)
2 #include<bits/stdc++.h>
3 #define int long long
4 #define F first
5 #define S second
6 #define P pair
7 #define FOR(i,a,b) for(int i=a;i<=b;i++)
8 #define V vector
9 #define RE return
10 #define ALL(a) a.begin(),a.end()
11 #define MP make_pair
12 #define PB push_back
13 #define PF push_front
14 #define FILL(a,b) memset(a,b,sizeof(a))
15 using namespace std;
16 int gcd(int a,int b){
17 if(!b)RE a;
18 RE gcd(b,a%b);
19 }
20 void solve(){
21 int a,m;
22 cin>>a>>m;
23 int t=gcd(a,m);
24 a/=t;m/=t;
25 int ans=m,la=m;
26 for(int i=2;i*i<=la;i++){
27 if(m%i==0){
28 while(m%i==0)m/=i;
29 ans=ans/i*(i-1);
30 }
31 }
32 if(m!=1){
33 ans=ans/m*(m-1);
34 }
35 cout<<ans<<'\n';
36 }
37 signed main(){
38 ios::sync_with_stdio(0);
39 cin.tie(0);
40 int t;
41 cin>>t;
42 while(t--)solve();
43 RE 0;
44 }
第五题:
我赛后也是用来将近1个多小时才解决,毕竟线段树太繁琐了,老是写不对。而且有的小错大部分数据都能过,就是有些过不了,急死我了。
这题也不是非常难,毕竟我15分钟就想出来怎么做了。
我们枚举最终得出的数组,再求出答案。
首先让所有的数都在第二个集合里,然后用一个数组表示一开始第一个数列取若干个数的时候总花费是多少。
从1开始,把数一个个往第一个里面挪。每挪一个,先求出这个数在原本数列里的位置。
如果在开始时第一个数列已经取了这个数,那么它就少花费了钱;如果第一个数列原本就没取它,那么反而增加了花费。
因为都是整区间覆盖,可以用线段树来实现,答案就是在所有出现过的答案之中选最小值。
上代码:

1 #pragma GCC optimize(3)
2 #include<bits/stdc++.h>
3 #define int long long
4 #define F first
5 #define S second
6 #define P pair
7 #define FOR(i,a,b) for(int i=a;i<=b;i++)
8 #define V vector
9 #define RE return
10 #define ALL(a) a.begin(),a.end()
11 #define MP make_pair
12 #define PB push_back
13 #define PF push_front
14 #define FILL(a,b) memset(a,b,sizeof(a))
15 using namespace std;
16 int n,a[200005],b[300000],l[600000],r[600000],zhi[600000],pf[600000],x[200005];
17 void dfs(int p,int l1,int r1,int d){
18 if(l[p]>r1||l1>r[p])RE;
19 if(l1<=l[p]&&r[p]<=r1){
20 pf[p]=pf[p]+d;zhi[p]=zhi[p]+d;
21 RE;
22 }
23 if(zhi[p]){
24 zhi[p*2]=zhi[p*2]+zhi[p];zhi[p*2+1]=zhi[p*2+1]+zhi[p];
25 pf[p*2]=pf[p*2]+zhi[p];pf[p*2+1]=pf[p*2+1]+zhi[p];
26 zhi[p]=0;
27 }
28 dfs(p*2,l1,r1,d);dfs(p*2+1,l1,r1,d);
29 pf[p]=min(pf[p*2],pf[p*2+1]);
30 }
31 signed main(){
32 ios::sync_with_stdio(0);
33 cin.tie(0);
34 cin>>n;
35 FOR(i,1,n)cin>>a[i],x[a[i]]=i;
36 FOR(i,1,n)cin>>b[i];
37 int ans=min(b[1],b[n]);
38 int m=1;
39 while(m<n)m*=2;
40 FOR(i,m,m*2-1){
41 l[i]=i-m+1;r[i]=l[i];
42 pf[i]=pf[i-1]+b[i-m+1];
43 }
44 for(int i=m-1;i>=1;i--){
45 l[i]=l[i*2];r[i]=r[i*2+1];
46 pf[i]=min(pf[i*2],pf[i*2+1]);
47 }
48 for(int i=1;i<n;i++){
49 if(x[i]>1)dfs(1,1,x[i]-1,b[x[i]]);
50 if(x[i]<n)dfs(1,x[i],n-1,-b[x[i]]);
51 ans=min(ans,pf[1]);
52 }
53 cout<<ans;
54 RE 0;
55 }
来源:https://www.cnblogs.com/njwsf/p/12244172.html
