训练报告 (2014-2015) 2014, Samara SAU ACM ICPC Quarterfinal Qualification Contest
Solved | A | Gym 100488A | Yet Another Goat in the Garden |
B | Gym 100488B | Impossible to Guess | |
Solved | C | Gym 100488C | Lost Temple |
Solved | D | Gym 100488D | Toy Soldiers |
Solved | E | Gym 100488E | Just Change a Word |
Solved | F | Gym 100488F | Two Envelopes |
Solved | G | Gym 100488G | Change-making Problem |
H | Gym 100488H | Tony Hawk's Pro Skater | |
Solved | I | Gym 100488I | Map Coloring |
J | Gym 100488J | Hyperdromes Strike Back | |
Solved | K | Gym 100488K | Two Pirates |
L | Gym 100488L | Two Heads Are Better | |
Solved | M | Gym 100488M | Construct a Permutation |
链接:2014, Samara SAU ACM ICPC Quarterfinal Qualification Contest
打了不到2个小时,3星
AC 4/13
真滴菜
A了4个题,然后挂机,然后溜了...
G 题没过滤掉无效情况
D 没考虑一开始就不用涂的情况
实际上
如果把M题,C题的时间拿来试A的题意,估计秒了
然后把I题的思路勇敢的推倒,搞个暴力,稳到5-6题也是可能的…
题解:
A 计算几何
出题人没说清楚题意,简直智障,求的确实是百分比,和我猜的一样...
很显然,把三个角的未覆盖放在一起,可以得到一个黑洞的外接三角形...
小三角形和大三角形的面积之比就是(黑洞的半径/大三角形内接圆半径)^2
大三角形的面积可以用海伦公式得到
然后小三角形的面积减去黑洞的面积就是没有覆盖的面积...
写的时候我一度以为是直角三角形..
#include <bits/stdc++.h> using namespace std; const int maxn=1e5+10; const int maxm=1e6+10; const int INF=0x3f3f3f3f; int casn,n,m,k; int a1[maxn],a2[maxn]; int main(){ //#define test #ifdef test freopen("in.txt","r",stdin);freopen("out1.txt","w",stdout); #endif double a,b,c,r; double PI=2.0*acos(0); double num[3]; while(cin>>num[0]>>num[1]>>num[2]>>r){ sort(num,num+3); a=num[0],b=num[1],c=num[2]; double l=(a+b+c)/2.0; double sum=sqrt(l*(l-a)*(l-b)*(l-c)); double R=2.0*sum/(a+b+c); double ss=sum*(r/R)*(r/R)-r*r*PI; double ans=(1.0-ss/sum); printf("%.16f\n",ans); } #ifdef test fclose(stdin);fclose(stdout);system("out1.txt"); #endif return 0; }
C
a*b=k(a+b)
给k 求所有的a和b
推一下公式 发现可以转化为a=k+(k^2)/(b-k)
所以只要得到k^2的所有因子,然后把这些因子+k就是b,k^2/这些因子再+k就是a...
显然 k^2的因字即k的因子,而k^2=k*k(废话),因此任意两个k的因子相乘,也一定是k^2的因子..
然后暴力就行了...
#include <bits/stdc++.h> #define ll long long using namespace std; const int maxn=1e5+10; const int maxm=1e6+10; const int INF=0x3f3f3f3f; ll casn,n,m,k; set<ll> vis; ll num[maxn]; int cnt=0; int main(){ //#define test #ifdef test freopen("in.txt","r",stdin);freopen("out1.txt","w",stdout); #endif while(cin>>k){ cnt=0; for(int i=1;i*i<=k;i++){ if(k%i) continue; num[cnt++]=i; if(i*i!=k) num[cnt++]=k/i; } vis.clear(); for(int i=0;i<cnt;i++){ for(int j=0;j<cnt;j++){ vis.insert(num[i]*num[j]); } } cout<<vis.size()<<endl; for(auto i=vis.begin();i!=vis.end();i++){ cout<<(*i+k)<<' '<<k+(k*k)/(*i)<<endl; } } #ifdef test fclose(stdin);fclose(stdout);system("out1.txt"); #endif return 0; }
D
水题
用map保存种颜色的数量,如果修改的过程中数量为零,则删除
当size==1的时候 结束
注意一开始就size==1的情况....
#include <string.h> #include <iostream> #include <algorithm> #include <stdio.h> #include <map> using namespace std; const int maxn=1e5+10; const int maxm=1e6+10; const int INF=0x3f3f3f3f; int casn,n,m,k; int a,b,c; int num[maxn]; map<int,int> vis; int main(){ // #define test #ifdef test freopen("in.txt","r",stdin);freopen("out.txt","w",stdout); #endif cin>>n; for(int i=1;i<=n;i++){ scanf("%d",&num[i]); vis[num[i]]++; } cin>>m; int ans=0; if(vis.size()==1) { ans=-1; } for(int i=1;i<=m;i++){ scanf("%d %d",&a,&b); if(ans) continue; if(vis.size()==1) { ans=i; } vis[num[a]]--; if(vis[num[a]]==0) vis.erase(num[a]); vis[b]++; num[a]=b; if(vis.size()==1) { ans=i; } } if(!ans)cout<<-1<<endl; else cout<<max(ans,0)<<endl; #ifdef test fclose(stdin);fclose(stdout);system("out.txt"); #endif return 0; }
E
水题
给一个字符串
每次找两个相邻的不同字母删除,问是否能删光
我想递推,但zc直接想出了只要统计是否有一种字符数量大于一半,大于则不可能
逻辑也比较显然,只要种类不是1种 就肯定能继续删下去,每次删除这两种字符都会--,但是如果一开始就大于一半,显然不可能,其他的情况必然有解
注意奇数情况
#include <string.h> #include <iostream> #include <algorithm> #include <stdio.h> #include <map> using namespace std; const int maxn=1e5+10; const int maxm=1e6+10; const int INF=0x3f3f3f3f; int casn,n,m,k; char s[maxm]; int vis[1000]; int main(){ //#define test #ifdef test freopen("in.txt","r",stdin);freopen("out.txt","w",stdout); #endif scanf("%s",s); n=strlen(s); int flag=1; if(n&1) flag=0; for(int i=0;i<n;i++){ vis[s[i]]++; } int cnt=0; for(int i=0;i<1000;i++){ cnt=max(vis[i],cnt); } if(cnt<=n/2&&flag) cout<<"YES"<<endl; else cout<<"NO"<<endl; #ifdef test fclose(stdin);fclose(stdout);system("out.txt"); #endif return 0; }
F
水题...
#include <string.h> #include <iostream> #include <algorithm> #include <stdio.h> using namespace std; const int maxn=1e5+10; const int maxm=1e6+10; const int INF=0x3f3f3f3f; int casn,n,m,k; int a,b,c; int main(){ //#define test #ifdef test freopen("in.txt","r",stdin);freopen("out.txt","w",stdout); #endif cin>>a>>b>>c; if(c>b) puts("Stay with this envelope"); else puts("Take another envelope"); #ifdef test fclose(stdin);fclose(stdout);system("out.txt"); #endif return 0; }
G
水题
直接贪心就好..
#include <string.h> #include <iostream> #include <algorithm> #include <stdio.h> using namespace std; const int maxn=1e5+10; const int maxm=1e6+10; int casn,n,m,k; #define IO ios::sync_with_stdio(false) long long a[maxn]; long long chu[maxn]; int main(){ IO; long long ans=0; while(cin>>n>>m) { for(int i=1;i<=n;i++) cin>>chu[i]; n++; memset(a,0,sizeof(a)); a[1]=1; int cnt=0; for(int i=2;i<=n;i++) { a[i]=a[i-1]*chu[i-1]; cnt=i; if(a[i]>1e11) { break; } } //cout<<a[2]<<endl; ans=0; int temp=0; n=cnt; for(int i=n;i>=1;i--) { if(a[i]==0) continue; temp=m/a[i]; ans+=temp; if(temp>0) { m-=a[i]*temp; } } cout<<ans<<endl; } return 0; }
I
给一个无向连通图,让你去染色,两点的颜色不同当且仅当两点相邻
比赛的时候题读错了,必须仔细读才行,幸亏给了sample3...不然得WA一天
不过一开始说dfs,也确实是可以dfs的...不过是在原图边集的补集上进行dfs,暴力上一种染色就行
以下是非dfs的n^2算法
#include <bits/stdc++.h> #define ll long long using namespace std; const int maxn=1e3+10; const int maxm=1e6+10; const int INF=0x3f3f3f3f; int casn,n,m,k; int g[maxn][maxn]; int clr[maxn]; int vis[maxn]; int main(){ //#define test #ifdef test freopen("in.txt","r",stdin);freopen("out1.txt","w",stdout); #endif while(cin>>n>>m>>k){ memset(g,0,sizeof g); for(int i=0;i<m;i++){ int a,b; scanf("%d%d",&a,&b); g[a][b]=g[b][a]=1; } memset(clr,0,sizeof clr); for(int i=1;i<=n;i++){ if(clr[i]) continue; memset(vis,0,sizeof vis); for(int j=1;j<=n;j++){ if(i!=j&&g[i][j]) vis[clr[j]]=1; } int tmp=1; while(vis[tmp])tmp++; clr[i]=tmp; } int flag=1; for(int i=1;i<=n&&flag;i++){ if(clr[i]>k||!clr[i]) flag=0; for(int j=i+1;j<=n&&flag;j++){ if(g[i][j]&&clr[i]==clr[j])flag=0; if(!g[i][j]&&clr[i]!=clr[j]) flag=0; } } if(flag){ for(int i=1;i<=n;i++) cout<<clr[i]<<' '; cout<<endl; }else puts("-1"); } #ifdef test fclose(stdin);fclose(stdout);system("out1.txt"); #endif return 0; }
K
两个人,n个物品顺序拜访,价值不同,轮流拿东西,只不过A先手,且每次可以任意拿,B后手且每次只能顺序拿剩下的
每次直接假设A拿走2个,然后每拿2个就把A拿过的最小的那个留给B,维护两人的和就行
简单来说,A可以选择让B拿走当前这个还是下一个,但A也可以拿后面的,让B既拿这个,也拿下一个
就用多重集合保存A可以拿的,每次把可以拿的最小的分给B即可
#include <bits/stdc++.h> using namespace std; const int maxn=1e5+10; const int maxm=1e6+10; const int INF=0x3f3f3f3f; int casn,n,m,k; multiset<int> vis; int main(){ //#define test #ifdef test freopen("in.txt","r",stdin);freopen("out.txt","w",stdout); #endif while(cin>>n){ vis.clear(); long long ans1=0,ans2=0; for(int i=1;i<=n;i++){ int t; cin>>t; ans1+=t; vis.insert(t); if(i%2==0){ ans1-=*vis.begin(); ans2+=*vis.begin(); vis.erase(vis.begin()); } } cout<<ans1<<' '<<ans2<<endl; } #ifdef test fclose(stdin);fclose(stdout);system("out.txt"); #endif return 0; }
M
给你A,B
要求一个长度为N的数列,为1-N的一个排列,其最长上升子序列长A,最长下降子序列长B,求N的最大值和对应的一种解
最长可达A*B
最终子序列由A段长度为B的下降子串构成,每一段下降串的最大值递增
例如
5 2
答案
10
2 1 4 3 6 5 8 7 10 9
#include <bits/stdc++.h> using namespace std; const int maxn=1e5+10; const int maxm=1e6+10; const int INF=0x3f3f3f3f; int casn,n,m,k; int a1[maxn],a2[maxn]; int main(){ //#define test #ifdef test freopen("in.txt","r",stdin);freopen("out1.txt","w",stdout); #endif int a,b; while(cin>>a>>b){ cout<<a*b<<endl; n=a*b; int cnt=1; for(int i=1;i<=a;i++){ for(int j=i*b;j>b*(i-1);j--){ cout<<j<<' '; } } cout<<endl; } #ifdef test fclose(stdin);fclose(stdout);system("out1.txt"); #endif return 0; }