A 题目链接:Problem - A - Codeforces
input:
9
1
1
1
2
2
2 4
3
3 6 9
4
5 10 15 20
5
120 60 80 40 80
6
150 90 180 120 60 30
6
2 4 6 9 12 18
6
30 60 90 120 125 125
output:
0
1
2
2
1
3
3
0
1
题意:给长度为n的数组a,给定一种操作,可以使任意 ai = gcd(ai,i),代价是n-i+1,问最少操作几次可以使整个数组的gcd为1
思路:数据量很小,直接对数组gcd一遍,如果为1,直接输出0.如果不满足,直接看后两个数变化后能否满足条件。只操作an,只操作an-1,和二者都操作的代价分别为1,2,3,暴力看一下哪个满足条件,输出最小的。
代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=25;
int t,n;
int a[N];
bool gcd()
{
int k=a[n];
for(int i=n-1;i>=1;i--)
{
k=__gcd(k,a[i]);
if(k==1)
return true;
}
if(k==1)
return true;
return false;
}
int main()
{
ios::sync_with_stdio(false);
cin>>t;
while(t--)
{
cin>>n;
int ans=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
if(gcd())
{
cout<<ans<<endl;
continue;
}
else
{
int an=a[n];
a[n]=__gcd(a[n],n);
if(gcd())
{
cout<<1<<endl;
continue;
}
else
{
a[n]=an;
a[n-1]=__gcd(a[n-1],n-1);
if(gcd())
{
cout<<2<<endl;
continue;
}
else
{
cout<<3<<endl;
continue;
}
}
}
}
return 0;
}
B 题目链接:https://codeforces.com/contest/1732/problem/B
input:
8
1
1
2
10
3
101
4
1100
5
11001
6
100010
10
0000110000
7
0101010
output:
0
1
2
1
2
3
1
5
题意:给长度为n的01串,给定一种操作,选定一个下表i,令所有下标不小于i的元素0变1,1变0,问最少操作多少次可以使序列变为不下降序列
思路:从序列中找到第一个1,然后此后的若干0,若干1为一个块,输出块的数量-1即可。因为第一个“1”块的后面必须全部变成1,才满足不下降,所以每一个块都需要付出一个代价
代码如下
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int t,n;
int main()
{
ios::sync_with_stdio(false);
cin>>t;
while(t--)
{
string s;
cin>>n;
cin>>s;
int cnt=0;
int i;
for(i=0;i<n;i++)
{
if(s[i]=='1')
break;
}
i++;
for(i;i<n;i++)
{
if(s[i]!=s[i-1])
cnt++;
}
cout<<cnt<<endl;
}
return 0;
}
C1,C2没做出来(枯了)明天补
D 题目链接:Problem - D1 - Codeforces
input:
15
+ 1
+ 2
? 1
+ 4
? 2
+ 6
? 3
+ 7
+ 8
? 1
? 2
+ 5
? 1
+ 1000000000000000000
? 1000000000000000000
output:
3
6
3
3
10
3
2000000000000000000
题意:给一个集合,最初只有一个0,每次给出两种操作:1.向集合中加入一个x(保证可以加入)2. 给一个k,问最小的能整除k的,且不在集合内的数是多少
思路:数大,注意开long long。这道题我们开了两个map,map1用来存集合,map2用来存k的最近一次询问的结果是多少。对于每一次询问k,先看一看map2里有没有记录,如果有的话,这一次可以从map2[k]开始找,就令k=map2[k]。然后k每次增长k,看集合里有没有这个值,没有的话直接输出。
代码如下
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int t;
map<ll,ll> mp1,mp2;
int main()
{
ios::sync_with_stdio(false);
cin>>t;
while(t--)
{
char c;
cin>>c;
ll k;
cin>>k;
if(c=='+')
{
mp1[k]=1;
continue;
}
else
{
ll i;
if(mp2.count(k)==0)
i=k;
else
i=mp2[k];
for(i;;i+=k)
{
if(mp1.count(i)==0)
{
cout<<i<<endl;
break;
}
}
mp2[k]=i;
}
}
return 0;
}
D2 题目链接:Problem - D2 - Codeforces
input:
18
+ 1
+ 2
? 1
+ 4
? 2
+ 6
? 3
+ 7
+ 8
? 1
? 2
+ 5
? 1
+ 1000000000000000000
? 1000000000000000000
- 4
? 1
? 2
output:
3
6
3
3
10
3
2000000000000000000
3
4
题意:上一题的困难版本,加入了一种操作‘-‘:选定集合中一个数,将其删除,其余均一样
思路:rank的时候没做出来,时间都花在c1上了,感谢@与风做友同学的强大思路。在上一题map1,map2基础上增加一个map3,用来存储哪些数被删过。在“+”操作中,如果加入进来的数曾经被删,也就是在map3中有记录,那就将其在map3中删除。在“-”操作中,将该数在map1中删除,并加入到map3中。查询时,如果map2中没有记录,就直接从k开始遍历,操作同D1.如果有记录,那么看map3,先找到第一个map3中不小于k的值,然后开始遍历,从删的数里面直接找满足条件的数,找到就输出,如果比map2[t]大了,就不如直接从map2[t]开始找。然后找到数以后输出
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e6+1;
typedef long long ll;
int T;
long long t;
map<ll,ll> mp1,mp2,mp3;
int main()
{
ios::sync_with_stdio(false);
cin>>T;
char op;
while(T--)
{
cin>>op>>t;
if(op=='+')
{
mp1[t]=1;
if(mp3.count(t)!=0) mp3.erase(t);
}
else if(op=='-')
{
mp1.erase(t);
mp3[t]=1;
}
else
{
ll i;
if(mp2.count(t)==0)
{
for(i=t;;i+=t)
{
if(mp1.count(i)==0)
{
cout<<i<<endl;
break;
}
}
mp2[t]=i;
}
else
{
bool f=0;
for(auto iter=mp3.lower_bound(t);iter != mp3.end(); iter++)
{
if(iter->first>mp2[t]) break;
if((iter->first)%t==0)
{
f=1;
cout<<iter->first<<endl;
break;
}
}
if(f) continue;
for(i=mp2[t];;i+=t)
{
if(mp1.count(i)==0)
{
cout<<i<<endl;
break;
}
}
mp2[t]=i;
}
}
}
return 0;
}