Codeforces Round #422 (Div. 2)

A I’m bored with life

题目要求
求两个数阶乘的gcd

#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 Crossword solving

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

#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 Hacker, pack your bags!

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

#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 My pretty girl Noora

题目要求
一场选美比赛有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)。求 t0⋅f(l)+t1⋅f(l+1)+⋯+t^r−l⋅f(r) 的最小值对1e9+7的模。

#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]。

posted @ 2018-03-16 09:07  foreignbill  阅读(98)  评论(0)    收藏  举报