2016 杭州区域赛补题
?
A - ArcSoft's Office Rearrangement
?HDU - 5933?
題意:現在有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\n" , cas);}else{long long tmp = sum/m; // printf("%lld..\n" , tmp);for(long long i=1; i<=n; i++){ // printf("%lld...%lld..\n" , 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\n" , cas , num);}}return 0; } View CodeF - Four Operations
?HDU - 5938
題意:給你一個字符串,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..\n" , 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..\n" , 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...\n" , i , maxx); }printf("Case #%d: %lld\n" , cas , maxx);}return 0; }/* 100 999999999999999999991224591224591 */ View CodeC - Car
?HDU - 5935
題意:現在一個人駕車行駛,保證全程不減速,現在給出了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...\n" ,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..\n" , i , tmp);ans += tmp;}printf("Case #%d: %lld\n" , cas , ans);}return 0; } View Code?
B - Bomb
?HDU - 5934
題意:現在有一對炸彈,要全部都引爆,每個炸彈有自己的圓心和半徑,引爆之后在范圍內的炸彈都會被引爆,問引爆所有炸彈所需要的最小的花費。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\n" , cas , ans);}return 0; } View Code?
D - Difference
?HDU - 5936??題意:現在定義一個操作,對于正整數,強調一下,是正整數,數字y的每一位的K次方-y=x,現在給定了x與k,求有多少種滿足條件的y
做法:x = F(y,k)-y
? ? ? ? ?因為? y > 0
? ? ? ? ?所以 x > F(y,k)
? ? ? ? ?因為 題目給定 x > 0
? ? ? ? ?所以? F(y,k) > y
? ? ? ? ?所以x > F(y,k) > y
? ? ? ? ?所以y的長度不超過x的長度10位,將y分成兩部分,低位部分a和高位部分b
? ? ? ? 設 F(Y,K) = F(a,k) +F(b,k);
? ? ? ? x =?F(a,k) +F(b,k)-a- b*1e5;
? ? ? ? x-F(a,k)+a = F(b,k)-b*1e5
? ? ? ? ?y 的個數就是使上式成立的數字的個數
? ? ? ?于是枚舉等式前邊的數字,時間復雜度O(100000),預處理出來等式后邊的,排序之后二分查找使之成立的個數即可
感謝:https://blog.csdn.net/luricheng/article/details/70176894提供思路與坑點
代碼如下:
#include<stdio.h> #include<iostream> #include<algorithm> #include<string.h> #include<math.h>using namespace std;const long long maxn = 100050;long long F[maxn]; long long t; long long x , k; long long ans[maxn];long long poww(long long n ,long long m) {long long res = 1;for(long long i=1; i<=m; i++){res *= n;}return res; }void init() {memset(F , 0 , sizeof(F));for(long long i=0; i<100000; i++){long long j = i;while( j ){F[i] += poww(j%10 , k);j /= 10;}ans[i] = F[i]-(i*100000);}sort(ans , ans+100000); }void debug() {for(long long i=0; i<=100; i++){printf("%lld...%lld...%lld\n" , i , F[i] , ans[i]);} }long long sea(long long xx) {long long L , R;L = lower_bound(ans , ans+100000 , xx)-ans;if(ans[L] != xx)return 0;R = upper_bound(ans , ans+100000 , xx)-ans;R--;if(ans[R] != xx)return 0;return R-L+1; }long long solve() {long long res;res = 0;for(long long i=0; i<100000; i++){long long tmp = sea(x-F[i]+i);res += tmp;}return res; }int main() {scanf("%lld" ,&t);for(long long cas=1; cas<=t; cas++){scanf("%lld%lld" , &x , &k);init(); // debug();long long tmp = solve();if(x == 0)tmp--;printf("Case #%lld: %lld\n" , cas , tmp);}return 0; } View Code?
?
E - Equation
?HDU - 5937?題意:現在你有一些數字卡片,每個數字卡片上寫有1~9中的一個,給你的是每一個數字有多少張卡片,問你能夠組成多少種不一樣的等式。
A+B=C 與 B+A=C 定義為不一樣的
思路:感謝https://www.cnblogs.com/jihe/p/6024135.html不然這個bug我能de一年
直接暴力哪幾個被選了就好,但是不能這樣暴力,就是你現在選的是第x個,下一個選第幾個,因為這樣只讓我們的暴力數量變多,我們其實想要的就是這個有沒有被選就好了
那么就從第一個開始,看他作為第i個的時候,下一個作為第i+1個,與此同時,下一層就是我不作為第i層,i+1作為第i層,這樣可以覆蓋所有的情況
代碼如下:
/* 錯因: 首先不剪枝會WA 其次,問的是會出現多少種不一樣的,而不是多少個 多少種的話,就可以整一個vis數組,最大容量是2,也就是2+3=5與3+2=5不一樣 但是容量是2的時候和直接保存兩個有區別嗎? 試一下*/#include<stdio.h> #include<iostream> #include<algorithm> #include<string.h>using namespace std;struct NODE {int a , b , c; } node[40]; int t; int maxx; int a[15]; int rem; int flag;void pre() {int tot = 0;for(int i=1; i<9; i++){for(int j=1; i+j<=9; j++){node[tot].a = i;node[tot].b = j;node[tot].c = i+j; // printf("%d..%d..%d..%d..\n" , tot , i , j , i+j);tot++;}} }void init() {maxx = 0;flag = 1;rem = 0; }void input() {for(int i=1; i<=9; i++){scanf("%d" , &a[i]);a[i] = min(a[i] , 17-i);rem += a[i];if(a[i] < 17-i)flag = 0;} }bool ok(int xx) {if(a[node[xx].a]>=0 && a[node[xx].b]>=0 && a[node[xx].c]>=0)return true;return false; }void dfs(int x , int dep , int sheng) {if(36-x+dep<=maxx) ///后面的全都可以也不行的話 就直接跳出return ;if(dep >= 36)return ;a[node[x].a] -= 1;a[node[x].b] -= 1;a[node[x].c] -= 1;if(ok(x)){maxx = max(maxx , dep+1);dfs(x+1 , dep+1 , sheng-3);}a[node[x].a] += 1;a[node[x].b] += 1;a[node[x].c] += 1;dfs(x+1 , dep , sheng); }void solve() {dfs(0 , 0 , rem); }int main() {pre();scanf("%d" , &t);for(int cas=1; cas<=t; cas++){init();input(); // printf("%d...\n" , rem);if(flag){printf("Case #%d: 36\n" , cas);continue;}solve();printf("Case #%d: %d\n" , cas , maxx);}return 0; } View Code?
轉載于:https://www.cnblogs.com/Flower-Z/p/9703607.html
總結
以上是生活随笔為你收集整理的2016 杭州区域赛补题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 解决问题:远程电脑时出现发生身份验证错误
- 下一篇: 畅捷通T+与畅捷通T+对接集成批量新增销