比赛链接: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;
}