比赛链接:http://codeforces.com/contest/797

A. k-Factorization

题意:将数n分解为k个大于1的数的乘积。

解法:模拟

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
vector<int>v;
int main(){
	int n, k;
	scanf("%d%d",&n,&k);
	for(int i=2;i<=n; i++){
		while(n%i==0){
			v.push_back(i);
			n/=i;
		}
	}
	if(k>v.size()) puts("-1");
	else{
        for(int i=0; i<k-1; i++) printf("%d ", v[i]);
        int ans=1;
        for(int i=k-1; i<v.size(); i++) ans*=v[i];
        printf("%d\n", ans);
	}
	return 0;
}
B. Odd sum

题意:从一个序列中挑选子序列,使得这个子序列的和是最大的奇数

解法:先考虑极端情况。1.所有的元素都是正的,容易想到是对这n个元素求和,判断是不是奇数,如果是 直接输出,如果不是,就减去n个元素中最小的偶数。2.所有的元素都是负的,那么直接找到最大的奇元素就好了,如果又有正的,又有负的,那么就对整数元素进行求和,盘算是不是奇数,如果是直接输出,如果不是,求max(最大整数和-最小正偶数,最大整数和+最大负偶数)

#include <bits/stdc++.h>
using namespace std;
int n, a[100010];
set<int>s1,s2;
int main(){
	scanf("%d",&n);
	for(int i=1; i<=n; i++) scanf("%d",&a[i]);
	int sum=0;
	for(int i=1; i<=n; i++){
		if(a[i]>0){
			sum+=a[i];
			s1.insert(a[i]);
		}else{
			s2.insert(abs(a[i]));
		}
	}
	if(sum%2==1){
		printf("%d\n", sum);
	}else{
		int ans1=-1e9, ans2=-1e9;
		if(s1.size()){
			int val=100000;
			for(set<int>::iterator it=s1.begin(); it!=s1.end(); it++){
				if((*it)%2==1){
					val=*it;
					break;
				}
			}if(val!=100000)
			ans1 = sum-val;
		}
		if(s2.size()){
			int val=100000;
			for(set<int>::iterator it=s2.begin(); it!=s2.end(); it++){
				if((*it)%2==1){
					val=*it;
					break;
				}
			}if(val!=100000)
			ans2 = sum-val;
		}
		printf("%d\n", max(ans1,ans2));
	}
	return 0;
}

C. Minimal string

题意:给你一个栈,然你找到一个出栈顺序,使得字典序最小。

解法:

逆序维护一个数组h[i]=x,表示第i个位子后边最小的字符是x.那么对应维护一个栈,如果此时栈顶字符小于等于h【此时要加入的元素的位子】,那么就出栈,将栈顶这个字符输出,同时每个字符都在操作结束后入栈。


#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
char s[maxn];
int n, h[30], top, toph, st[maxn];

int main(){
    scanf("%s", s+1);
    n = strlen(s+1);
    for(int i=1; i<=n; i++) h[s[i]-'a']++;
    top=toph=0;
    for(int i=1; i<=n; i++){
        st[++top] = s[i]-'a';
        h[s[i]-'a']--;
        for(;toph<26&&!h[toph];) ++toph;
        for(;top&&st[top]<=toph;--top) printf("%c",'a'+st[top]);
    }
    for(;top;--top) printf("%c", 'a'+st[top]);
    printf("\n");
    return 0;
}

D. Broken BST

题意:n<=1e5的树,最多有两个分支,要求按照排序二叉树的方式询问值是否存在,求出错的次数(即a[i]存在但是找不到)?

解法:若暴力查询 最坏时,树退化成链O(n^2)  因为是树 使用root->值x路径唯一,一个值x能被查询到,当且仅当从root起往值x走的路径中,端点p向右走的值都比x小,端点q向左走的值都比x大则x>=max(p) && x<=min(q) 


#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010;
const int inf = 0x3f3f3f3f;
struct node{
    int l,r,v;
}t[maxn];
int n,root;
bool rt[maxn];
map<int,int>mp;
void dfs(int x,int p,int q){
    if(x==-1) return;
    if(t[x].v>=p&&t[x].v<=q){
        if(mp[t[x].v]) mp[t[x].v]=0;
    }
    dfs(t[x].l,p,min(q,t[x].v));
    dfs(t[x].r,max(t[x].v,p),q);
}
int main(){
    memset(rt,true,sizeof(rt));
    mp.clear();
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d%d",&t[i].v,&t[i].l,&t[i].r);
        if(t[i].l!=-1) rt[t[i].l]=0;
        if(t[i].r!=-1) rt[t[i].r]=0;
        mp[t[i].v]++;
    }
    for(int i=1;i<=n;i++) if(rt[i]) root=i;
    dfs(root,-inf,inf);
    int ans=0;
    for(int i=1;i<=n;i++){
        ans+=mp[t[i].v];
        mp[t[i].v]=0;
    }
    printf("%d\n",ans);
    return 0;
}

E. Array Queries
题意:如题上公式。

解法: 所有的k值保存不下, 这里我保存k值小于200的dp值, d[p][k]  (k < 200), 当k大于200时直接模拟。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
int n, q, k, p;
int dp[maxn][205], a[maxn];
int solve(int p, int k){
    if(p>n) return 0;
    else if(k<200){
        if(~dp[p][k]) return dp[p][k];
        dp[p][k] = solve(p+a[p]+k,k)+1;
        return dp[p][k];
    }else{
        return solve(p+a[p]+k,k)+1;
    }
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    memset(dp,-1,sizeof(dp));
    scanf("%d",&q);
    while(q--){
        scanf("%d%d",&p,&k);
        printf("%d\n", solve(p,k));
    }
    return 0;
}
F. Mice and Holes



#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 5003;
struct node{
    LL x,v;
    bool operator<(const node&rhs)const{
        return x<rhs.x;
    }
}hole[maxn];
LL mice[maxn],sum[maxn],pre[maxn],dp[maxn][maxn]; //dp[i][j]前i个洞被j只老鼠占据的最小步数
//dp[i][j] = min(dp[i-1][k]+sum[i][j]-sum[i][k])
//dp[i][j] = min(dp[i-1][k]-sum[i][k]) + sum[i][j]
int que[maxn];
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    memset(dp, 0x3F, sizeof(dp));
    for(int i=1;i<=n;i++) scanf("%lld",&mice[i]);
    for(int i=1;i<=m;i++) scanf("%lld%lld",&hole[i].x,&hole[i].v);
    sort(mice+1,mice+n+1);
    sort(hole+1,hole+m+1);
    for(int i=1;i<=m;i++) pre[i]=pre[i-1]+hole[i].v;
    if(pre[m]<n) return 0*puts("-1");
    dp[0][0]=0;
    for(int i=1;i<=m;i++){
        dp[i][0]=0;
        int l=0,r=0;
        que[++r]=0;
        for(int j=1;j<=pre[i]&&j<=n;j++){
            dp[i][j]=dp[i-1][j];
            sum[j]=sum[j-1]+abs(mice[j]-hole[i].x);
            while(j-que[l]>hole[i].v) ++l;
            while(l<=r&&dp[i-1][que[l]]-sum[que[l]]>dp[i-1][j]-sum[j]) ++l;
            que[++r]=j;
            dp[i][j]=min(dp[i][j],(LL)sum[j]+dp[i-1][que[l]]-sum[que[l]]);
        }
    }
    printf("%lld\n", dp[m][n]);
    return 0;
}