2018 ICPC Asia Nanjing Regional Contest

solve: 5/13

Practice link:https://vjudge.net/contest/388613#overview

A - Adrien and Austin

题意:给你 n 个石头,编号从1~n,有两个人,每个人每次操作只能从石头中取 1~k 个连续编号的石头,最后不能取的一方为输,问谁会赢。

思路:先手必输状态:1、k==1且 n%2==0

                                    2、n==0

代码:

 1 int main()
 2 {
 3      int n,k;
 4      scanf("%d %d",&n,&k);
 5      if(n==0||(k==1&&n%2==0)){
 6        cout<<"Austin"<<endl;
 7      }else{
 8        cout<<"Adrien"<<endl;
 9      }
10      return 0;
11 } 
View Code

D - Country Meow

题意:给你 n 个三维方向上的点,让你建立一个中心指挥部,使这个点到这些点的最大距离最短。

思路:模拟退火求最小球覆盖

代码:

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 #define MOD 998244353 
 4 #define INF 0x3f3f3f3f
 5 #define mem(a,x) memset(a,x,sizeof(a))  
 6 #define _for(i,a,b) for(int i=a; i< b; i++)
 7 #define _rep(i,a,b) for(int i=a; i<=b; i++)
 8 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
 9 using namespace std;const double eps=1e-7;
10 struct point3D
11 {
12     double x,y,z;
13 } data[35];
14 ll n;
15 double dis(point3D a,point3D b)
16 {
17     return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z));
18 }
19 double solve()
20 {
21     double step=100000,ans=1e30,mt;
22     point3D z;
23     z.x=z.y=z.z=0;
24     ll s=0;
25     while(step>eps)
26     {
27         for(int i=0; i<n; i++)
28             if(dis(z,data[s])<dis(z,data[i])) s=i;
29         mt=dis(z,data[s]);
30         ans=min(ans,mt);
31         z.x+=(data[s].x-z.x)/mt*step;
32         z.y+=(data[s].y-z.y)/mt*step;
33         z.z+=(data[s].z-z.z)/mt*step;
34         step*=0.98;
35     }
36     return ans;
37 }
38 int main()
39 { // freopen("t.txt","r",stdin);
40     double ans;
41     scanf("%d",&n);
42         for(int i=0; i<n; i++)
43             scanf("%lf%lf%lf",&data[i].x,&data[i].y,&data[i].z);
44         ans=solve();
45         printf("%.15f
",ans);
46     return 0;
47 }
View Code

G - Pyramid

题意:如下图所示,给你一个边长为 n 的等边三角形,问你在这个三角形中有多少个等边三角形。

           

思路:打表找规律,可以推得 num = n*(n+1)*(n+2)*(n+3)/24,因为要取余操作且式子中有除法,因此要求24的逆元,再取余即可。

代码:

 1 void extend_gcd(ll a,ll b,ll &x,ll &y)
 2 {
 3     if(b==0) {
 4         x=1,y=0;
 5         return;
 6     }
 7     extend_gcd(b,a%b,x,y);
 8     ll tmp=x;
 9     x=y;
10     y=tmp-(a/b)*y;
11 }
12 ll mod_inverse(ll a,ll m)
13 {
14     ll x,y;
15     extend_gcd(a,m,x,y);
16     return (m+x%m)%m;
17 }
18 int main()
19 {    
20    ll T,n;
21     scanf("%lld",&T);
22     while(T--){
23         scanf("%lld",&n);
24         ll sum=1;
25         for(int i=0;i<=3;i++)
26         {
27             sum=sum*(n+i)%Mod;
28         }
29         ll k=mod_inverse(24,Mod);
30         sum=((sum%Mod)*(k%Mod))%Mod;
31         printf("%lld
",sum);
32     }
33 }
View Code

I - Magic Potion

题意:有 n 个英雄和 m 个怪兽,每个英雄有可以打到的怪兽的集合且每个英雄只能打一个怪兽。又有 k 瓶药,每个英雄至多用一瓶,一瓶药可以使一个英雄多打一个怪兽。问你最多有几个怪兽被打。

思路:这题可以看出是一道二分图最大匹配题,首先把一个英雄拆成两个点,每个点都与可以打的怪兽建边,求这个图的最大匹配 ans,然后不考虑有药的情况求二分图的最大匹配 ans2,接下来看条件,如果

 ans2+k<=ans,则输出 ans2+k,否则输出 ans 即可。

代码:

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 #define MOD 998244353 
 4 #define INF 0x3f3f3f3f
 5 #define mem(a,x) memset(a,x,sizeof(a))  
 6 #define _for(i,a,b) for(int i=a; i< b; i++)
 7 #define _rep(i,a,b) for(int i=a; i<=b; i++)
 8 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
 9 using namespace std;
10 const int maxn = 1000005;
11 const int NUM = 1e4+5;
12 int n,m,k,flag,ans;
13 int link[NUM];
14 bool vis[NUM];
15 vector<int>g[4*NUM];
16 bool dfs(int x)
17 {
18     for(int i=0;i<g[x].size();i++){
19         int v=g[x][i];
20         if(!vis[v]){
21             vis[v]=1;
22             if(!link[v]||dfs(link[v])){
23                 link[v]=x;
24                 return true;
25             }
26         }
27     }
28     return false;
29 }
30 int main()
31 {
32     scanf("%d %d %d",&n,&m,&k);
33     ans=0;
34     mem(link,0);
35     for(int i=1;i<=n;i++){
36         int t;
37         scanf("%d",&t);
38         for(int j=1;j<=t;j++){
39             int x;
40             scanf("%d",&x);
41             g[i].push_back(2*n+x);
42             g[n+i].push_back(2*n+x);
43         }
44     }
45     for(int i=1;i<=2*n;i++){
46         mem(vis,0);
47         if(dfs(i))ans++;
48     }
49     int ans2=0;
50     mem(link,0);
51     for(int i=1;i<=n;i++){
52         mem(vis,0);
53         if(dfs(i))ans2++;
54     }
55         if(ans2+k<=ans){
56             cout<<ans2+k<<endl;
57         }else{
58             cout<<ans<<endl;
59         }
60     return 0;
61 }
View Code

J - Prime Game

题意:给你 n 个数,定义    , 为 的不同的质因数的个数。求 。

思路:应该考虑每个素数因子对答案的贡献,首先对于 第p个元素含有某个素数因子,则该元素对答案的贡献为 ( n - p + 1 )*p。接下来考虑有重复的情况出现,比如说 第 k 个元素(在p之前)也有某个素数因子,则该元素对答案的贡献为 ( n - k + 1 )*k,则第 p 个元素的贡献就变成了 ( n - p + 1 )*( p - k)。然后我们用 pos[ i ][ k ]储存素数因子 i 第 k 次出现的位置,那么我们只需要遍历每个素数因子 i 让sum=sum+ (n - pos[ i ][ k ] + 1)*( pos[ i ][ k ] - pos[ i ][ k - 1])即可,注意让 pos[ i ][ 0 ] = 0。

代码:

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 #define MOD 998244353 
 4 #define INF 0x3f3f3f3f
 5 #define mem(a,x) memset(a,x,sizeof(a))  
 6 #define _for(i,a,b) for(int i=a; i< b; i++)
 7 #define _rep(i,a,b) for(int i=a; i<=b; i++)
 8 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
 9 using namespace std;
10 const int maxn = 1000005;
11 const int NUM = 1e4+5;
12 
13 int n,a[maxn];
14 vector<int>pos[maxn];
15 void dec(int p)
16 {
17     int n=a[p];
18     for(int i=2;i*i<=n;i++){
19         if(n%i==0)
20         {
21             pos[i].push_back(p);
22             while(n%i==0)n/=i;   //
23         }
24     }
25     if(n>1)pos[n].push_back(p);
26 }
27 int main()
28 {
29     scanf("%d",&n);
30     for(int i=2;i<=1000000;i++)pos[i].push_back(0);
31     for(int i=1;i<=n;i++){
32         scanf("%d",&a[i]);
33         dec(i);
34     }
35     ll sum=0;
36     for(int i=2;i<=1000000;i++){
37         for(int k=1;k<pos[i].size();k++){
38             sum+=(ll)(n-pos[i][k]+1)*(pos[i][k]-pos[i][k-1]);
39         }
40     }
41     cout<<sum;
42     return 0;
43 }
View Code

K - Kangaroo Puzzle

题意:在一个20×20的地图上,11表示有袋鼠,00表示有障碍物,边界外和障碍物上不能走。
要求给出一个50000步以内的操作,每一步操作为'L', 'R', 'U', 'D', 表示所有袋鼠一起动的方向,如果某个袋鼠下一个地方是不能走的,那么它那一步会忽略,使得所有袋鼠都聚集在一起。

思路:因为20x20非常小且有50000步可以操作,因此随机输出50000个  'L', 'R', 'U', 'D', 即可。(神奇)

代码:

 1 char a[25][25];
 2 int main()
 3 {
 4     int n,m;
 5     scanf("%d %d",&n,&m);
 6     getchar();
 7     for(int i=1;i<=n;i++){
 8         scanf("%s",a);
 9     }
10     n=50000;
11     char s[5]="URLD";
12     while(n--){
13         printf("%c",s[rand()%4]);
14     }
15     return 0;
16 }
View Code

 

越自律,越自由
原文地址:https://www.cnblogs.com/ha-chuochuo/p/13473039.html