2017-2018 ACM-ICPC NEERC Southern Subregional Contest(3)
*A. Automatic Door
题意
分析
*C
题意
分析
*G
题意
分析
签到
F. Lost in Transliteration
签到
M. Quadcopter Competition
签到
H. Palindromic Cut
题意
给一个长度为n的字符串,尽可能的少的分成长度相同的回文串,输出回文串个数,以及每个回文串
分析
考虑回文串,直接将字符分成两类,能回文的长度为2的串(eg:aa),长度为1的串(eg:a),然后暴力分别算出数量令前者sum1,后者sum2,暴力找到sum1%sum2==0的情况(2可以分成两个1),然后输出即可
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<algorithm> #include<cstdio> #include<cstdlib> #include<string> #include<cstring> #include<cmath> #include<vector> #include<set> #include<map> #include<stack> #include<queue> #include<time.h> #define ll long long using namespace std; #define mp make_pair #define pb push_back #define lson l,mid,pos<<1 #define rson mid+1,r,pos<<1|1 const double PI=acos(-1); const int maxm=2000+5; //const int maxn=1e5+5; const int mod=1e9+7; const int inf=0x3f3f3f3f; const ll INF = 0x3f3f3f3f3f3f3f3fLL; const double eps=1e-8; //int dir[4][2]={0,1,1,0,0,-1,-1,0}; //ll gcd(ll a,ll b){return b?gcd(b,a%b):a;} //ll lcm(ll a,ll b){return a/gcd(a,b)*b;} //ll inv(ll b){if(b==1)return 1; return (mod-mod/b)*inv(mod%b)%mod;} //ll fpow(ll n,ll k){ll r=1;for(;k;k>>=1){if(k&1)r=r*n%mod;n=n*n%mod;}return r;} vector<char> odd,even; int n,cnt[300]; char str[400010], ans[400010]; int main() { scanf("%d",&n); scanf("%s",str+1); for (int i=1;i<=n;i++) cnt[str[i]]++; for (int i=0;i<=256;i++) if (cnt[i]) { if (cnt[i]&1) { cnt[i]--; odd.push_back(i); } for (int j=1;j<=cnt[i]/2;j++) even.push_back(i); } if (odd.size()==0) { for (int i=1;i<=n/2;i++) ans[i]=ans[n-i+1]=even[i-1]; printf("1\n"); for (int i=1;i<=n;i++) printf("%c",ans[i]); return 0; } else { while (even.size()%odd.size()) { odd.push_back(even.back()); odd.push_back(even.back()); even.pop_back(); } printf("%d\n",(int)odd.size()); for (int i=1;i<=(int)odd.size();i++) { ans[(n/odd.size())/2]=odd[i-1]; for (int j=1;j<=n/odd.size()/2;j++) ans[(n/odd.size()/2)-j]=ans[(n/odd.size()/2)+j]=even.back(),even.pop_back(); for (int j=0;j<n/odd.size();j++) printf("%c",ans[j]); printf(" "); } } return 0; }
*I. Photo Processing
题意
给n个数分组,每组至少分k个数(不要求连续分),每组的mex值为每组的max-min,这n个数的mex为所有组mex的max,使这个max最小,并求出这个数
分析
很容易下想到,二分答案,check(mid)用dp,dp[i]表示1~i可以分组的最远位置
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<algorithm> #include<cstdio> #include<cstdlib> #include<string> #include<cstring> #include<cmath> #include<vector> #include<set> #include<map> #include<stack> #include<queue> #include<time.h> #include<unordered_map> #include<unordered_set> #define ll long long using namespace std; #define mp make_pair #define pb push_back #define lson l,mid,pos<<1 #define rson mid+1,r,pos<<1|1 const double PI=acos(-1); const int maxm=2000+5; const int maxn=3e5+5; const int mod=1e9+7; const int inf=0x3f3f3f3f; const ll INF = 0x3f3f3f3f3f3f3f3fLL; const double eps=1e-8; //int dir[4][2]={0,1,1,0,0,-1,-1,0}; //ll gcd(ll a,ll b){return b?gcd(b,a%b):a;} //ll lcm(ll a,ll b){return a/gcd(a,b)*b;} //ll inv(ll b){if(b==1)return 1; return (mod-mod/b)*inv(mod%b)%mod;} //ll fpow(ll n,ll k){ll r=1;for(;k;k>>=1){if(k&1)r=r*n%mod;n=n*n%mod;}return r;} int n, k; int a[maxn]; int dp[maxn]; bool check(int answer) { int id = 0; for(int i = k; i <= n; i++) { int point = dp[i-k]; if((a[i]-a[dp[i-k]+1]) <= answer) id = i; dp[i] = id; } if(dp[n] == n) return true; else return false; } int main() { scanf("%d%d", &n, &k); for(int i = 1; i <= n;i++) { scanf("%d", &a[i]); } sort(a+1,a+n+1); int l = 0, r = 1000000000; while(l < r) { int mid = (l+r)/2; if(check(mid)) { r = mid; } else { l = mid+1; } } printf("%d\n", l); return 0; }
K. Road Widening
题意
给n条路,每条路都有一个初始的宽度和一个最多可以加的宽度,现要求每条路的最终宽度S[i],满足 |s'i + 1 - s'i| ≤ 1 (1 <= i < n)都成立,问所有路最多能加多少(和)以及每条路最终的宽度, 没有满足条件的解输出-1
分析
分析可得这道题和两个区间的关系有一定联系(六种情况)?
首先可以否定的是从前往后或者从后往前尽可能多的取,因为可能不满足题意,其实很直观的是维护每个点的合法区间(通过上下两个区间关系,画出两个区间观察就可以看出来),下面就是如何维护合法区间,从前往后扫一边维护每一个点的合法区间的左右端点,从前往后扫的时候 i 和 i-1形成了一个制约关系, 不难理解一个位置i的值得确定和左右两边的数都有关系,所以在从后往前扫一遍求出每个位置具体的值即可
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; const int maxn = 2e5 + 5; int n; int a[maxn], g[maxn], xmax[maxn], xmin[maxn]; int now[maxn]; int main() { scanf("%d", &n); long long sum = 0, ans = 0; for(int i = 1; i <= n; i++) { scanf("%d%d", &a[i], &g[i]); g[i] = a[i]+g[i]; } xmax[1] = g[1]; xmin[1] = a[1]; for(int i = 2; i <= n; i++) { xmax[i] = min(g[i], xmax[i-1]+1); xmin[i] = max(a[i], xmin[i-1]-1); if(xmax[i] < xmin[i]) { printf("-1\n"); return 0; } } sum += xmax[n] - a[n]; ans = xmax[n]; now[n] = xmax[n]; for(int i = n-1; i >= 1; i--) { if(ans+1 <= xmax[i]) ans = ans+1; else if(ans<=xmax[i]) ans =ans; else ans = ans -1; now[i]=ans; sum += ans-a[i]; } printf("%I64d\n", sum); for(int i = 1; i <= n; i++) printf("%d%c", now[i],i==n?'\n':' '); return 0; }