奋斗群群赛3总结与心得(缺5)

来源:互联网 发布:php所有的数据类型 编辑:程序博客网 时间:2024/05/18 14:42

  • 总体情况
  • T1
    • 题目
    • 思路与两个小时的过程
  • T2
    • 题目
    • 思路
  • T3
    • 题目
    • 思路
  • T4
    • 题目
    • 思路

总体情况

我在3个小时30分钟内A了1,2,4三题,剩下的两道我不会,我就发我借来的代码了。
https://cn.vjudge.net/contest/183502

T1

题目

对于输入的五个正整数l,r,x,y,k,若存在正整数l<=i<=r,x<=j<=y,使得i/j=k,输出“YES”,否则输出”NO”.

思路与两个小时的过程

我在这个题上发生的故事很多,让我细细道来。我AC这个题的时间是2小时48分26秒,提交8次AC.
我知道l/y是最小值,r/x是最大值,第一次的时候我以为只要k在这个范围里面,就一定有这种可能。看来我还是太年轻了。

#include<bits/stdc++.h>using namespace std;int main(){double l,r,x,y,k;cin>>l>>r>>x>>y>>k;if (l/y<=k&&r/x>=k) cout<<"YES";else cout<<"NO";}

输入 10 10 3 4 3的时候,虽然2.5<=3<=3.33,可是你找不到这样的i,j,使得i/j=3.所以我开始O(N^2)的爆搜,TLE.

#include<bits/stdc++.h>using namespace std;int main(){double l,r,x,y,k,i,j;cin>>l>>r>>x>>y>>k;if (r/x<k||l/y>k) {cout<<"NO";return 0;}for (i=l;i<=r;i++)for (j=x;j<=y;j++) if (i/j==k) {cout<<"YES";return 0;}cout<<"NO";}

我知道不能爆搜,我想,就用int,否则什么事情都会发生。
因为i/j=k,故k*j=i.第五次我只枚举j,看乘出来的i是不是在l和r之间。

#include<bits/stdc++.h>using namespace std;int main(){int l,r,x,y,k,i;cin>>l>>r>>x>>y>>k;if (k*x>r||k*y<l) cout<<"NO";else   {   for (i=x;i<=y;i++) if (i*k>=l&&i*k<=r) {cout<<"YES";return 0;}  cout<<"NO";  }  }

再一次WA了。我把判定k是不是在范围内去掉,改成直接搜。

#include<bits/stdc++.h>using namespace std;int main(){int l,r,x,y,k,i;cin>>l>>r>>x>>y>>k;for (i=x;i<=y;i++) if (i*k>=l&&i*k<=r) {cout<<"YES";return 0;}cout<<"NO";  }

还是WA。中间我休息了几次去做别的题,结果搞了好久才A了第2题,做第4题也是屡屡碰壁。
后来我想,k<=1000000,i<=1000000,乘出来会不会爆int啊?我在电脑上编译运行,能很好地输出,可是这玩意一到评测机上就瘪了。我改成long long,又交了第8次。下附AC代码。

#include<bits/stdc++.h>using namespace std;int main(){long long l,r,x,y,k,i;cin>>l>>r>>x>>y>>k;for (i=x;i<=y;i++) if (i*k>=l&&i*k<=r) {cout<<"YES";return 0;}cout<<"NO";  }

事实证明,看看有没有爆int实在太重要了!东方星莲船当中总分数貌似就爆了int,当分超过2147483647的时候就会减分.

T2

题目

在平面直角坐标系中以原点为圆心有一个大环形,大圆半径是r,大圆和小圆之间的距离是d,以下给出很多圆形的圆心坐标和半径,输出全部落在环形中的圆形总数。

思路

当时在做的时候看错了题目,把d看成了小圆的半径,一直没对.具体方法就是看每一个圆的圆心加上和减去半径,看看它是不是在圆环内.操作简单易行,分分钟A了.

#include<bits/stdc++.h>using namespace std;double n,m,x[100010],y[100010],r[100010];bool in[100010];int main(){int i,k,s=0;cin>>n>>m>>k;for (i=1;i<=k;i++) cin>>x[i]>>y[i]>>r[i];for (i=1;i<=k;i++)   {  if (sqrt(x[i]*x[i]+y[i]*y[i])+r[i<=n&&sqrt(x[i]*x[i]+y[i]*y[i])-  r[i]>=n-m) in[i]=1;  }for (i=1;i<=k;i++) if (in[i]==1) s++;cout<<s;}

T3

题目

由于时间有限,直接发题目链接.
http://codeforces.com/problemset/problem/842/C

思路

dfs.

#include<bits/stdc++.h>using namespace std;const int boss=2e5;vector<int> v[boss+10];set<int> s[boss+10];int n,x,y,a[boss+10];int gcd(int a,int b){return b==0?a:gcd(b,a%b);}void dfs(int root,int father,int r){for (set<int>::iterator i=s[father].begin();i!=s[father].end();i++) s[root].insert(gcd(*i,a[root]));s[root].insert(r);for (int i=0;i<v[root].size();i++) if (v[root][i]!=father) dfs(v[root][i],root,gcd(r,a[root]));}int main(){int i;cin>>n;for (i=1;i<=n;i++) scanf("%d",&a[i]);for (i=1;i<=n-1;i++)   {  scanf("%d%d",&x,&y);  v[x].push_back(y);  v[y].push_back(x);  }s[0].insert(0);dfs(1,0,0);for (i=1;i<=n;i++) printf("%d ",*s[i].rbegin());} 

T4

题目

对于一串正整数,我们要让这串数字里的所有数的最大公约数比1大,可以进行这样的操作:让第i个数字变成第i个数字和第i+1个数字的差,同时让第i+1个数字变成第i个数字和第i+1个数字的和.问能否进行n次这样的操作使得这串数字符合题目条件?若能,输出”YES”,换行输出n;若不能,输出”NO”.

思路

明显一定是可能的,输出”YES”.然后我先对这串数字判断一下看看它们的最大公约数是不是已经比1大了.然后我发现题目所述操作的规律.如果操作的数是两个奇数,结果是两偶;如果操作的数是一奇一偶,结果是两奇.故用最短的方法能把所有数变成偶数,可以符合题目条件.代码如下.

#include<bits/stdc++.h>using namespace std;int a[100010];int gcd(int a,int b){if (b==0) return a;else return gcd(b,a%b);}int main(){int n,i,j,s=0;cin>>n;for (i=1;i<=n;i++) scanf("%d",&a[i]);int g=a[1];for (i=2;i<=n;i++) {g=gcd(g,a[i]);if (g==1) break;} if (g>1) {cout<<"YES\n0";return 0;}//如果最大公约数已经大于1,输出0for (i=1;i<=n-1;i++)  {  if (a[i]%2==1&&a[i+1]%2==1) {s++;a[i]++;a[i+1]++;i++;}//两奇,操作一下变两偶  else if (a[i]%2==1&&a[i+1]%2==0) {a[i]++;s+=2;}//前奇后偶,操作两次变偶  } if (n%2==1&&a[n]%2==1) s+=2;//如果一共有奇数个,最后那个是奇数,操作两次else if (n%2==0&&a[n]%2==1&&a[n-1]%2==0) s+=2;//一共有偶数个,最后是偶奇,也操作两次cout<<"YES\n"<<s;  }