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 }
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 }
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 }
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 }
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 }
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 }