2016 杭州区域赛补题
Posted flower-z
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2016 杭州区域赛补题相关的知识,希望对你有一定的参考价值。
A - ArcSoft‘s Office Rearrangement
题意:现在有n个办公区,每个办公区内有a[i]个办公人员,现在要将这些人均匀的分布在m个办公区内,每个办公区人员必须等价。现在有两个操作,1操作,可以将相邻的两个区域的人员结合在一起,2操作可以将一个办公区的人员,随意划分成两部分,两部分不一定平均,问最少需要多少次操作。
做法:贪心,从前向后枚举,不可以的情况就是不能平均的,可以预处理出来平均值,对于可以的情况,如果比平均值小,就直接加在后一个办公区内,要是与平均值一样,就可以直接跳过,要是大于平均值,就先划分成平均值的若干份,最后不足一个平均值的加在后一个办公区内。
代码如下:
#include<stdio.h> #include<iostream> using namespace std; long long t; long long n , m; long long a[100005]; long long sum; long long num; int main() { scanf("%lld" , &t); for(long long cas = 1; cas<=t; cas++) { scanf("%lld%lld" , &n , &m); sum = 0; num = 0; for(long long i=1; i<=n; i++) { scanf("%lld" , &a[i]); sum += a[i]; } if(sum % m != 0) { printf("Case #%lld: -1 " , cas); } else { long long tmp = sum/m; // printf("%lld.. " , tmp); for(long long i=1; i<=n; i++) { // printf("%lld...%lld.. " , i , a[i]); if(a[i] > tmp) { num += (a[i]/tmp)-1; if(a[i]%tmp != 0) { num ++; //先剥离下来 num++; //再安装到下一个块上去 a[i+1] += a[i]%tmp; } } else if(a[i] == tmp) { continue; } else if(a[i]<tmp && a[i]!=0) { num++; a[i+1] += a[i]; } } printf("Case #%lld: %lld " , cas , num); } } return 0; }
F - Four Operations
题意:给你一个字符串,5<=len<=20,字符串由1~9的数字组成,问你向里面按顺序添加+ - * / 构成的算术运算式子结果最大是多少
做法:我们知道肯定让x+y尽可能的大,a*b/c的结果尽可能小,于是a*b的结果尽可能小,c尽可能大。
于是我们枚举“/”的位置,后面的作为c,a,b都只占一位 前面的作为x+y,一直x+y的长度之后,例如12121,那么和要尽可能大,要么就是1+2121,要么就是1212+1,因为这样可以保证尽可能长的长度,为什么要枚举除法的位置,而不是直接取最后一位,给前面省长度呢,因为可能a*b很大,c很小,导致我们减去的东西很大,比一位所带来的影响还要大,例如224591,所以需要枚举"/"的位置
代码如下:
#include<stdio.h> #include<iostream> #include<algorithm> #include<string.h> using namespace std; int t; char s[25]; int len; long long sum[25]; long long maxx; long long num(int l , int r) { long long res = 0; for(int i=l; i<=r; i++) { res = res*10+(s[i]-‘0‘); } return res; } int main() { scanf("%d" , &t); for(int cas=1; cas<=t; cas++) { scanf("%s" , s); len = strlen(s); maxx = -100000000000000000; // printf("%lld.. " , maxx); for(int i=0; i<len; i++) { // sum[i] =0; // for(int j=0; j<i; j++) // { // sum[i] = max(sum[i] , num(0,j)+num(j+1,i)); // } sum[i] = max(num(1,i)+(s[0]-‘0‘) , num(0,i-1)+(s[i]-‘0‘)); // printf("%d..%lld.. " , i , sum[i]); } for(int i=4; i<len; i++) { maxx = max(maxx , sum[i-3]-((s[i-2]-‘0‘)*(s[i-1]-‘0‘)/num(i,len-1))); // printf("%d...%lld... " , i , maxx); } printf("Case #%d: %lld " , cas , maxx); } return 0; } /* 100 99999999999999999999 1224591 224591 */
C - Car
题意:现在一个人驾车行驶,保证全程不减速,现在给出了n个测速点,保证测速点一定是在整秒的时候测量的,问这个人通过这n个测速点最快的时间
做法:正向的,全程不减速不好写,对于每一段,你无法确定速度与时间,如果这一段比上一段长,你就直接设置成一秒,那万一下一段很短,岂不是前面的设置都错了;
于是我们反向想,倒过来就是全程不加速,那么最后一段一定是一秒,速度最大,这样可以保证全程时间尽可能的短,于是最后一段的时间与速度都是知道的,那么前一段的速度要小于这一段,时间要尽可能的短,于是整除向上取整即可,记得更新速度,即可解决
坑点:不能直接计算速度v 精度卡的非常的死 必须保存距离与时间
代码如下:
#include<stdio.h> #include<iostream> #include<algorithm> #include<math.h> #include<string.h> using namespace std; int t; int n; long long b[100005]; long long a[100005]; //long long num1 , num2; void debug() { for(int i=1; i<=n; i++) { printf("%d..%lld... " ,i , a[i]); } } int main() { scanf("%d" , &t); for(int cas=1; cas<=t; cas++) { scanf("%d" , &n); // num1 = 0; b[0] = 0; for(int i=1; i<=n; i++) { scanf("%lld" , &b[i]); // a[i] = num2-num1; // num1 = num2; } sort(b+1 , b+1+n); for(int i=1; i<=n; i++) { a[i] = b[i]-b[i-1]; } // debug(); long long ans = 1; // double v = a[n]*1.00; long long tmp; tmp = 1; for(int i=n-1; i>=1; i--) { tmp = ceil((1.00*a[i]*tmp)/a[i+1]); // printf("%d..%lld.. " , i , tmp); ans += tmp; } printf("Case #%d: %lld " , cas , ans); } return 0; }
B - Bomb
题意:现在有一对炸弹,要全部都引爆,每个炸弹有自己的圆心和半径,引爆之后在范围内的炸弹都会被引爆,问引爆所有炸弹所需要的最小的花费。n<=1e3
做法:刚开始的做法是,首先,我们可以根据引爆范围n^2的建图,有向图,入度为零的是一定要点的,它所能到达的点全部都删去, 剩下的就是在连通块中找最小花费的点了。剩下的这部分我是直接联通快中招最小点的。 这样是一定不对的,例如,1-2 2-3 3-1 2-4 4的值最小,但是引爆4并不能引爆1,2,3. 于是,只有在同一个强连通分量里面才可以求最小值,剩下的就是入度为零的全部引爆了 于是,先缩点,形成DAG之后求 Tarjan的时间复杂度O(n+m) 缩点时间复杂度O(n^2) 求解O(n)
代码如下:
/* 刚开始的做法是:首先,我们可以根据引爆范围n^2的建图,有向图,入度为零的是一定要点的,它所能到达的点全部都删去, 剩下的就是在连通块中找最小花费的点了。剩下的这部分我是直接联通快中招最小点的。 这样是一定不对的,例如,1-2 2-3 3-1 2-4 4的值最小,但是引爆4并不能引爆1,2,3. 于是,只有在同一个强连通分量里面才可以求最小值,剩下的就是入度为零的全部引爆了 于是,先缩点,形成DAG之后求 Tarjan的时间复杂度O(n+m) 缩点时间复杂度O(n^2) 求解O(n) */ #include<stdio.h> #include<iostream> #include<algorithm> #include<string.h> #include<math.h> using namespace std; const int maxn = 1003; int t; int n; struct CIRCLE { double x,y; double r; int c; }circle[maxn]; double dis(int i , int j) { return sqrt((circle[i].x-circle[j].x)*(circle[i].x-circle[j].x)+(circle[i].y-circle[j].y)*(circle[i].y-circle[j].y)); } void input() { for(int i=1; i<=n; i++) { scanf("%lf%lf%lf%d" , &circle[i].x , &circle[i].y , &circle[i].r , &circle[i].c); } } struct EDGE { int to , next; }edge[maxn*maxn]; int head[maxn] , tot; //int head2[maxn] , tot2; int ans; int du[maxn]; int low[maxn] , dfn[maxn] , Stack[maxn] , num[maxn];///num记录缩点之后每个点的大小 int belong[maxn]; int index , scc , top; bool InStack[maxn]; void init() { memset(head , -1 , sizeof(head)); tot = 0; // memset(head2 , -1 , sizeof(head2)); // tot2 = 0; ans = 0; for(int i=1; i<=n; i++) { num[i] = 10004; } memset(du , 0 , sizeof(du)); } void add(int u , int v) { edge[tot].to = v; edge[tot].next = head[u]; head[u] = tot++; } //void add2(int u , int v) //{ // edge2[tot2].to = v; // edge2[tot2].next = head2[u]; // head2[u] = tot2++; //} void build() { for(int i=1; i<=n; i++) { for(int j=1; j<=n; j++) { if(j == i) continue; if(dis(i , j) <= circle[i].r) { add(i , j); } } } } void Tarjan(int u) { int v; low[u] = dfn[u] = ++index; Stack[top++] = u; InStack[u] = true; for(int i=head[u]; i!=-1; i=edge[i].next) { v = edge[i].to; if( !dfn[v] ) { Tarjan(v); if( low[u] > low[v] ) { low[u] = low[v]; } } else if(InStack[v] && low[u] > dfn[v]) { low[u] = dfn[v]; } } if(low[u] == dfn[u]) { scc++; do { v = Stack[--top]; InStack[v] = false; belong[v] = scc; num[scc] = min(num[scc] , circle[v].c); }while(v!=u); } } void solve() { memset(dfn , 0 , sizeof(dfn)); memset(InStack , false , sizeof(InStack)); index = scc = top = 0; for(int i=1; i<=n; i++) { if( !dfn[i] ) { Tarjan(i); } } for(int i=1; i<=n; i++) { for(int j=head[i]; j!=-1; j=edge[j].next) { int tmp = edge[j].to; if(belong[i] != belong[tmp]) { // add2(belong[i] , belong[tmp]); du[belong[tmp]]++; } } } } int main() { scanf("%d" , &t); for(int cas=1; cas<=t; cas++) { scanf("%d" , &n); init(); input(); build(); solve(); for(int i=1; i<=scc; i++) { if(du[i] == 0) { ans += num[i]; } } printf("Case #%d: %d " , cas , ans); } return 0; }
以上是关于2016 杭州区域赛补题的主要内容,如果未能解决你的问题,请参考以下文章