2017-2018 ACM-ICPC Latin American Regional Programming Contest
http://codeforces.com/gym/101889
A
B - Buggly ICPC
在写一串字符串时,每当写到元音字母就会时整体字符串翻转一次,问得到目标字符串有几种书写方式。
分情况讨论,只有辅音时只有一种,每次翻转必有一个元音字母到首位,多个元音存在时,只与最开始要书写的元音字母有关。
#include <iostream> #include <cstdio> #include <cstring> using namespace std; char s[100005]; int vis[100005],ans=0; bool match(char ch){ if(ch=='a' || ch=='e' || ch=='i' || ch=='o' || ch=='u') return true; return false; } int main(){ scanf("%s",s); int pos=0,flag=false; memset(vis,0,sizeof(vis)); for(int i=0;s[i];i++){ if(i==0 && match(s[i])) flag=true; if(match(s[i])){ vis[ans]=pos; pos=0; ans++; } else pos++; } vis[ans]=pos; if(ans==0) printf("1\n"); else if(!flag) printf("0\n"); else{ int k=ans/2+1; if(ans&1) printf("%d\n",vis[k]+1); else printf("%d\n",vis[k-1]+1); } return 0; }
C - Complete Naebbirac's sequence
给你一个k和一个n,然后给你n个数,现在要你只操作一次,加一个数或者减一个数,使得所有的数次出现的次数相等,若不能得到,输出*;
所有的数字不会超过K,若输出+号或者-号,说明只能出现一次,首先得出每个数字出现的平均次数t=(n+1)/k,因此vector标记下,讨论下即可,看题目,k>=3,
上式成立,若K等于1,则答案不唯一。
#include <bits/stdc++.h> #pragma GCC diagnostic error "-std=c++11" using namespace std; int n,k,a[1006]; vector<int>add,sub,mid; int main(){ scanf("%d%d",&k,&n); for(int i=0,x;i<n;i++){ scanf("%d",&x); a[x]++; } int t=(n+1)/k; for(int i=1;i<=k;i++){ if(a[i]==t) continue; else if(a[i]==t+1) add.push_back(i); else if(a[i]==t-1) sub.push_back(i); else mid.push_back(i); } if(add.size()==1 && !sub.size() && !mid.size()) printf("-%d\n",add[0]); else if(!add.size() && sub.size()==1 && !mid.size()) printf("+%d\n",sub[0]); else if(!mid.size() && sub.size()==1 && add.size()==1) printf("-%d +%d\n",add[0],sub[0]); else printf("*\n"); return 0; }
D
E - Enigma
给你一个文本s由?和数字字符组成,?可以被任意数字字符代替,问得出最小的数字可以整除N。
记忆话搜索
#include <bits/stdc++.h> #pragma GCC diagnostic error "-std=c++11" using namespace std; int vis[1003][1003]; bool pos[1003][1003]; string ans,s; int n,m,len; bool dfs(int idx,int res){ if(idx>=len) return res==0; if(vis[idx][res]) return pos[idx][res]; vis[idx][res]=1; if(s[idx]=='?'){ for(int i=!idx;i<=9;i++){ pos[idx][res]=max(pos[idx][res],dfs(idx+1,(res*10+i)%n)); if(pos[idx][res]) return true; } } else pos[idx][res]=max(pos[idx][res],dfs(idx+1,(res*10+(s[idx]-'0'))%n)); return pos[idx][res]; } void solve(int idx,int res){ if(idx==len) return ; if(s[idx]=='?'){ for(int i=!idx;i<=9;i++){ if(dfs(idx+1,(res*10+i)%n)){ ans+=(char)(i+'0'); solve(idx+1,(res*10+i)%n); return ; } } } else{ ans+=s[idx]; solve(idx+1,(res*10+(s[idx]-'0'))%n); return ; } } int main(){ cin>>s>>n; len=s.size(); if(dfs(0,0)){ solve(0,0); cout<<ans<<endl; } else printf("*\n"); return 0; }
F - Fundraising
有n个人,每个人有自己的美丽值,财富值,和贡献度,现在挑选若干人,并且,只有两个人的财富值和美丽值完全相等或者一个人的财富值和美丽值完全大于另一个人才不会起冲突,问在不起冲突的条件下可以得到的最大贡献值是多少。
离散化线段树。
将每个人的财富值即纵坐标离散,然后排序,每次查询即在二维坐标系中找斜率大于0的直线。注意有重点。
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=100006; int n,m; vector<int>v; struct Node{ int x,y; ll v; bool operator<(const Node &b) const{ return b.x==x?b.y>y:b.x>x; } }a[maxn],e[maxn]; ll vis[100006][2]; struct tree { ll val; int left,right; }tree[maxn<<2]; void PushUp(int root){ tree[root].val=max(tree[root<<1].val,tree[root<<1|1].val); } void build(int l,int r,int root) { tree[root].val=0; tree[root].left=l; tree[root].right=r; if(l==r) return ; int mid=l+r>>1; build(l,mid,root<<1); build(mid+1,r,root<<1|1); PushUp(root); } void update(int root,int pos,ll val) { if(tree[root].left==tree[root].right){ tree[root].val=max(val,tree[root].val); return ; } int mid=tree[root].left+tree[root].right>>1; if(pos<=mid) update(root<<1,pos,val); else update(root<<1|1,pos,val); PushUp(root); } ll query(int root,int l,int r) { if(l>r) return 0; if(l<=tree[root].left && r>=tree[root].right){ return tree[root].val; } int mid=tree[root].left+tree[root].right>>1; ll ans=0; if(l<=mid) ans=max(ans,query(root<<1,l,r)); if(r>mid) ans=max(ans,query(root<<1|1,l,r)); return ans; } int get_id( int x ){ return lower_bound(v.begin(),v.end(),x)-v.begin()+1; } int main(){ scanf("%d",&n); for( int i=0; i<n ;i++){ scanf("%d%d%lld",&a[i].x,&a[i].y,&a[i].v); v.push_back(a[i].y) ; } sort(v.begin(),v.end()) ; v.erase(unique(v.begin(),v.end()),v.end()); sort(a,a+n); m=v.size(); build(1,m,1); ll inf=0; int tot=-1,l=0; for(int i=0;i<n;i++){ if(i && a[i].x==a[i-1].x && a[i].y==a[i-1].y){ e[tot].v+=a[i].v; } else{ tot++; e[tot].x=a[i].x; e[tot].y=get_id(a[i].y); e[tot].v=a[i].v; } } e[++tot].x=1000000007; vis[0][1]=e[0].v; for(int i=0;i<tot;i++){ ll ans=query(1,1,e[i].y-1); vis[i][0]=ans+e[i].v; if(e[i].x!=e[i+1].x){ for(int j=l;j<=i;j++) update(1,e[j].y,vis[j][0]); l=i+1; } } printf("%lld\n",query(1,1,m)); return 0; }
G
H - Hard choice
已知航班提供的三种盒饭的数量,然后给出每种盒饭有多少乘客想要,问有多少人吃不上饭。
#include <bits/stdc++.h> using namespace std; int a[4]; int main(){ int ans=0; for(int i=0;i<3;i++) scanf("%d",&a[i]); for(int i=0,x;i<3;i++){ scanf("%d",&x); ans+=max(0,x-a[i]); } printf("%d\n",ans); return 0; }
I
J - Jumping Frog
一个字符串只有RP组成,R代表岩石,P代表池塘,frog只能从岩石开始起跳,并且不能中途调到池塘里,每次可以跳K步,只要最后可以跳回起始点,则此K可取
问K有多少种取法。
gcd的应用
#include <bits/stdc++.h> #pragma GCC diagnostic error "-std=c++11" using namespace std; char s[100005]; bool vis[100005]; int len; int main(){ scanf("%s",&s); len=strlen(s); for(int i=1;i<len;i++){ if(len%i) continue; for(int j=0;j<i;j++){ vis[i]=1; for(int k=0;k<=len/i;k++){ if(s[k*i+j]=='P'){ vis[i]=0; break; } } if(vis[i]) break; } } int ans=0; for(int i=1;i<len;i++) if(vis[__gcd(i,len)]) ans++; printf("%d\n",ans); return 0; }
K