2017ACM/ICPC亚洲区沈阳站-重现赛
HDU 6222 Heron and His Triangle
链接:http://acm.hdu.edu.cn/showproblem.php?pid=6222
思路: 打表找规律+大数运算
首先我们可以打个表暴力跑出前几个满足题意的T
打表代码:
#include<bits/stdc++.h> using namespace std; bool fun(double n) { if(abs(round(n) - n) < 0.000000000000001) return 1; return 0; } int main() { for(int i = 2;i <= 10000000;i ++){ double num = (i+1)*sqrt(3*(i-1)*(i+3))/4; if(fun(num)) cout<<i+1<<endl; } }
打出表后会得到: 4,14,52,194,724等数据。。。经过推导我们会得到他们之间的公式: a[i] = a[i-1]*4-a[i-2],然后我们用大数模板去跑这串公式就好了
实现代码:
#include<bits/stdc++.h> using namespace std; /*bool fun(double n) { if(abs(round(n) - n) < 0.000000000000001) return 1; return 0; } int main() { for(int i = 2;i <= 10000000;i ++){ double num = (i+1)*sqrt(3*(i-1)*(i+3))/4; if(fun(num)) cout<<i+1<<endl; } }*/ string Mult(string s,int x) //大数乘以整形数 { reverse(s.begin(),s.end()); int cmp=0; for(int i=0;i<s.size();i++) { cmp=(s[i]-'0')*x+cmp; s[i]=(cmp%10+'0'); cmp/=10; } while(cmp) { s+=(cmp%10+'0'); cmp/=10; } reverse(s.begin(),s.end()); return s; } string sub(string a,string b) { string c; bool ok=0; int len1=a.length(); int len2=b.length(); int len=max(len1,len2); for(int i=len1;i<len;i++) a="0"+a; for(int i=len2;i<len;i++) b="0"+b; if(a<b) { string temp=a; a=b; b=temp; ok=1; } for(int i=len-1;i>=0;i--) { if(a[i]<b[i]) { a[i-1]-=1; a[i]+=10; } char temp=a[i]-b[i]+'0'; c=temp+c; } int pos=0; while(c[pos]=='0' && pos<len) pos++; if(pos==len) return "0"; if(ok) return "-"+c.substr(pos); return c.substr(pos); } string s1[61]; int main() { int t; cin>>t; string s; s1[1] = "4";s1[2] = "14"; for(int i = 3;i <= 60;i ++) s1[i] = sub(Mult(s1[i-1],4),s1[i-2]); while(t--){ cin>>s; for(int i = 1;i <= 60;i ++) if(s1[i].size() > s.size()||(s1[i].size()==s.size()&&s1[i]>=s)){ cout<<s1[i]<<endl; break; } } return 0; }
HDU 6223 Infinite Fraction Path
链接:http://acm.hdu.edu.cn/showproblem.php?pid=6223
思路:bfs + 剪枝
算比较容易的bfs,一直没怎么写bfs,差点写自闭了。。。。调了半天才过。
实现代码:
#include<bits/stdc++.h> using namespace std; const int M = 4e5+10; #define ll long long int vis[M]; //判断当前点是否被访问过了 int n,a[M],top; int cnt[M]; //储存当前层被标记点的下标 int mx[M]; //每一层的最大值 struct node{ long long id; int val,step; }; //优先排步数小的,步数相等优先值大的 bool operator < (node a,node b){ if(a.step == b.step) return a.val < b.val; return a.step > b.step; } priority_queue<node> q; void bfs(){ int last = -1; while(!q.empty()){ node now = q.top(); q.pop(); if(now.step != last) { //已经步入下一层了清空上一层的标记 last = now.step; while(top) vis[cnt[--top]] = 0; } //限制条件剪枝 if(now.step == n) continue; if(vis[now.id]) continue; //当前点被访问过了,跳过 if(mx[now.step] > now.val) continue; //当前点小于这一层的最大值,跳过 //维护标记 cnt[top++] = now.id; vis[now.id] = 1; mx[now.step] = now.val; //将下一个点扔进队列中 node next; next.id = (now.id*now.id+1)%n;; next.val = a[next.id]; next.step = now.step+1; q.push(next); } for(int i = 0;i < n;i ++) printf("%d",mx[i]); for(int i = 0;i <= n;i ++) mx[i] = 0; printf("\n"); } char s[M]; int main() { int maxx,t; scanf("%d",&t); int t1 = t; while(t--){ top = 0; scanf("%d",&n); maxx = 0; scanf("%s",s); for(int i = 0;i < n;i ++){ a[i] = s[i]-'0'; maxx = max(maxx,a[i]); } mx[0] = maxx; for(int i = 0;i < n;i ++) if(a[i] == maxx){ node now; now.id = i;now.val = a[i],now.step = 0; q.push(now); } printf("Case #%d: ",t1-t); bfs(); } return 0; }
HDU 6225 Little Boxes
链接:http://acm.hdu.edu.cn/showproblem.php?pid=6225
大数加法
签到题
实现代码:
#include<bits/stdc++.h> using namespace std; string sum(string s1,string s2) { if(s1.length()<s2.length()) { string temp=s1; s1=s2; s2=temp; } int i,j; for(i=s1.length()-1,j=s2.length()-1;i>=0;i--,j--) { s1[i]=char(s1[i]+(j>=0?s2[j]-'0':0)); if(s1[i]-'0'>=10) { s1[i]=char((s1[i]-'0')%10+'0'); if(i) s1[i-1]++; else s1='1'+s1; } } return s1; } int main() { int n; string x; cin>>n; for(int i = 1;i <= n;i ++){ string ans = "0"; for(int j = 1;j <= 4;j ++){ cin>>x; ans = sum(ans,x); } cout<<ans<<endl; } return 0; }
HDU 6227 Rabbits
链接:http://acm.hdu.edu.cn/showproblem.php?pid=6227
思路: 求兔子最多跳的次数,排个序,两种情况取最大的:
第一种: 第二小的和最大的之间距离之差减去中间已经有位置的值
第二种: 倒着跳,第二大的和最小的距离之差减去中间已经有位置的值
签到题
实现代码:
#include<bits/stdc++.h> using namespace std; int a[20200]; int main() { int t,n,x; scanf("%d",&t); while(t--){ scanf("%d",&n); for(int i = 1;i <= n;i ++) scanf("%d",&a[i]); sort(a+1,a+1+n); int ans = max(a[n]-a[2]-n+2,a[n-1]-a[1]-n+2); printf("%d\n",ans); } return 0; }
HDU 6228 Tree
链接:http://acm.hdu.edu.cn/showproblem.php?pid=6228
思路:
要求公共子集最大,我们肯定是优先选择距离大的两点染成相同的颜色(因为要留位置给其他颜色),要达到公共边最多,那么我们可以先对边进行分析,如果一条边左边结点的子树大于k,右边结点的子树也大于k那么这条边可以成为公共子集的一条因为我们是要求最大的,根据最优策略,肯定要将他加进最大公共子集中,找到这种边+1就好了。
实现代码;
#include<bits/stdc++.h> using namespace std; const int M = 1e5 + 10; vector<int>g[M]; int ans,n,k,siz[M]; void dfs(int u,int fa){ siz[u] = 1; for(int i = 0;i < g[u].size();i ++){ int v = g[u][i]; if(v == fa) continue; dfs(v,u); siz[u] += siz[v]; if(siz[v] >= k&&(n-siz[v])>=k) ans++; } } int main() { int t,x,y; scanf("%d",&t); while(t--){ memset(siz,0,sizeof(siz)); scanf("%d%d",&n,&k); for(int i = 1;i <= n;i ++) g[i].clear(); for(int i = 1;i < n;i ++){ scanf("%d%d",&x,&y); g[x].push_back(y); g[y].push_back(x); } ans = 0; dfs(1,-1); printf("%d\n",ans); } }