cf round 422

cf round 422

A

题目要求

求两个数阶乘的gcd

参考AC代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include<bits/stdc++.h>
#define maxn 100000
#define inf 0x3f3f3f3f
#define LL long long
#define pb push_back
#define pii pair<int,int>
#define fi first
#define se second
#define mm(a,b) memset(a,b,sizeof(a))
#define mp(a,b) make_pair(a,b)
const LL mod=1e9+7;
const LL INF=(LL)1e18;
using namespace std;
int main(){
// freopen("input.txt","r",stdin);
// freopen("ouput.txt","w",sdout);
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
LL a,b;
cin>>a>>b;
LL c=min(a,b);
LL ans=1;
while(c){
ans*=c;
c--;
}
cout<<ans<<endl;
return 0;
}

思路

(max-min)!

B

题目要求

给出字符串s1和s2
要求最少改动s1中的多少个字母可以满足s1是s2的一个子串

参考AC代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include<bits/stdc++.h>
#define maxn 100000
#define inf 0x3f3f3f3f
#define LL long long
#define pb push_back
#define pii pair<int,int>
#define fi first
#define se second
#define mm(a,b) memset(a,b,sizeof(a))
#define mp(a,b) make_pair(a,b)
const LL mod=1e9+7;
const LL INF=(LL)1e18;
using namespace std;
int main(){
// freopen("input.txt","r",stdin);
// freopen("ouput.txt","w",sdout);
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int n,m;
cin>>n>>m;
string s1,s2;
cin>>s1>>s2;
int ans=inf;
int po=0;
for(int i=0;i<m-n+1;i++){
int st=i,ed=st+n-1;
int cur_po=0,cur_ans=0;
for(int j=st;j<=ed;j++){
if(s2[j]!=s1[cur_po++]) cur_ans++;
}
if(cur_ans<ans){
ans=cur_ans;
po=st;
}
}
cout<<ans<<endl;
int len=0;
for(int i=po;i<=po+n-1;i++) if(s2[i]!=s1[len++]) cout<<len<<" ";
cout<<endl;
return 0;
}

思路

用一个length1的窗口去滑动s2 记录下需要改变的字母的最小值和最小值的起始位置
最后判断下起始位置的子串 输出具体位置即可

C

题目要求

有n个区间 每个区间有左端点 右端点和cost值 输入需要满足的区间长度k
要从n个区间里选择若干个区间 满足他们互不相交 总的区间长度为k 并且cost和最小

参考AC代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include<bits/stdc++.h>
#define maxn 500050
#define LL long long
#define pb push_back
#define pii pair<int,int>
#define fi first
#define se second
#define mm(a,b) memset(a,b,sizeof(a))
#define mp(a,b) make_pair(a,b)
const LL mod=1e9+7;
const LL inf=(LL)1e18;
using namespace std;
struct node{
LL st,interval,cost;
int flag;
node(LL st,LL interval,LL cost,int flag):st(st),interval(interval),cost(cost),flag(flag){}
};
int cmp(node a,node b){
if(a.st==b.st) return a.flag>b.flag;
return a.st<b.st;
}
vector<node>s;
LL dp[maxn];
int main(){
// freopen("input.txt","r",stdin);
// freopen("ouput.txt","w",sdout);
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
LL n,x;
cin>>n>>x;
for(int i=1;i<=n;i++){
LL l,r,c;
cin>>l>>r>>c;
s.pb(node(l,r-l+1,c,1));
s.pb(node(r,r-l+1,c,-1));
}
for(int i=0;i<maxn;i++) dp[i]=inf;
LL ans=inf;
sort(s.begin(),s.end(),cmp);
for(int i=0;i<s.size();i++){
if(s[i].flag==1){
LL temp=x-s[i].interval;
if(temp<0) continue;
ans=min(ans,dp[temp]+s[i].cost);
}
else dp[s[i].interval]=min(dp[s[i].interval],s[i].cost);
}
if(ans<inf) cout<<ans<<endl;
else cout<<"-1"<<endl;
return 0;
}

思路

dp
dp[interval]表示之前所有点中满足区间长度是interval的最小cost值
每个区间拆分成两个端点 1代表左端点 -1代表右端点
所有的点升序排序 大小相同的点左端点优先
对于每个点 如果是左端点 更新ans值 如果是右端点 更新dp值
更新ans:temp表示除去该点剩下的区间长度 若temp>=0 dp[temp]即表示之前的状态中inetrval是temp的最小价值 加上该点的cost值更新答案
更新dp:如果到了右端点 说明某个区间已经更新好ans值 此时应该更新dp 用dp(之前的min)和该点的cost值取最小值即可
注意开LL
inf由于开了LL为1e18 不能取0x3f3f3f3f 所以不能用memset 要遍历初始化

D

题目要求

一场选美比赛有N个人,可以分成N/x,每组x人。每组的比较次数为x(x-1)/2,f[N]为最后决出冠军所需的比较次数,可以通过改变x的值使f[N]改变。
题目给出t,l,r(1 ≤ t < 109 + 7, 2 ≤ l ≤ r ≤ 5·106)。求 t^0⋅f(l)+t^1⋅f(l+1)+⋯+t^r−l⋅f(r) 的最小值对1e9+7的模。

参考AC代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include<bits/stdc++.h>
#define maxn 5000050
#define inf 0x3f3f3f3f
#define LL long long
#define pb push_back
#define pii pair<int,int>
#define fi first
#define se second
#define mm(a,b) memset(a,b,sizeof(a))
#define mp(a,b) make_pair(a,b)
const LL mod=1e9+7;
const LL INF=(LL)1e18;
using namespace std;
int vis[maxn+50];
LL prime[maxn+50],len=0;
LL f[maxn+50];
void solve(){
mm(vis,0);
vis[0]=vis[1]=1;
int m=sqrt(maxn+0.5);
for(LL i=2;i<=m;i++){
if(!vis[i]){
for(int j=i*i;j<=maxn;j+=i) vis[j]=1;
}
}
for(LL i=0;i<maxn;i++){
if(!vis[i]) prime[len++]=i;
}
}
int main(){
// freopen("input.txt","r",stdin);
// freopen("ouput.txt","w",sdout);
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
solve();
mm(f,0);
LL t,l,r;
cin>>t>>l>>r;
for(LL i=2;i<maxn;i++){
if(!vis[i]) f[i]=(i*(i-1)/2)%mod;
else{
LL factor;
for(LL j=0;j<len;j++){
if(i%prime[j]==0){
factor=prime[j];
break;
}
}
f[i]=(i/factor*f[factor]+f[i/factor])%mod;
}
}
LL ans=0;
for(LL i=r;i>=l;i--){
ans=(ans*t)%mod;
ans=(ans+f[i])%mod;
}
cout<<ans<<endl;
return 0;
}

思路

数论
如果人数为素数,那f[N]=N(N-1)/2;
如果不是素数,那就找出最小素因子x,分成N/x组,每组x人,f[N]=N/x*f[x]+f[N/x]。

文章目录
  1. 1. cf round 422
    1. 1.1. A
      1. 1.1.1. 题目要求
      2. 1.1.2. 参考AC代码
      3. 1.1.3. 思路
    2. 1.2. B
      1. 1.2.1. 题目要求
      2. 1.2.2. 参考AC代码
      3. 1.2.3. 思路
    3. 1.3. C
      1. 1.3.1. 题目要求
      2. 1.3.2. 参考AC代码
      3. 1.3.3. 思路
    4. 1.4. D
      1. 1.4.1. 题目要求
      2. 1.4.2. 参考AC代码
      3. 1.4.3. 思路
|