传送门:https://atcoder.jp/contests/abc190
A:
Takahashi和Aoki分别有A和B颗糖果,两人轮流吃一个,若C为0则Takahashi先吃,C为1则Aoki先吃,先吃完的为输。
1 #include <iostream> 2 #include <cstdio> 3 #include <vector> 4 #include <algorithm> 5 #include <queue> 6 #include <vector> 7 #include <map> 8 #include <cstdlib> 9 #include <cstring> 10 #include <cmath> 11 typedef long long ll; 12 const int INF=0x3f3f3f3f; 13 using namespace std; 14 int a,b,c; 15 int main(void) 16 { 17 cin>>a>>b>>c; 18 if(c==0) 19 { 20 if(a>b)cout<<"Takahashi"<<endl; 21 else cout<<"Aoki"<<endl; 22 } 23 else 24 { 25 if(a<b)cout<<"Aoki"<<endl; 26 else cout<<"Takahashi"<<endl; 27 } 28 return 0; 29 }
B:
Takahashi有N段符咒,每段需要吟唱Xi秒,伤害为Yi,而怪兽能免疫吟唱时间在S秒及以上和伤害在D及以下的符咒,问能否对怪兽造成伤害。
1 #include <iostream> 2 #include <cstdio> 3 #include <vector> 4 #include <algorithm> 5 #include <queue> 6 #include <vector> 7 #include <map> 8 #include <cstdlib> 9 #include <cstring> 10 #include <cmath> 11 typedef long long ll; 12 const int INF=0x3f3f3f3f; 13 using namespace std; 14 int n,s,d; 15 int main(void) 16 { 17 cin>>n>>s>>d; 18 while(n--) 19 { 20 int x,y; 21 cin>>x>>y; 22 if(x>=s||y<=d)continue; 23 cout<<"Yes"<<endl; 24 return 0; 25 } 26 cout<<"No"<<endl; 27 return 0; 28 }
C:
有N个盘子和M个状态,第i个状态满足当且仅当第Ai和第Bi个盘子上有一个以上的球。有K个人,每个人可以把一个球放在第Ci或者第Di个盘子上。求能满足的最多状态数。
分析:由于K<=16,那么总的情况数只有216种,因此可以直接暴搜,每次更新答案即可。
1 #include <iostream> 2 #include <cstdio> 3 #include <vector> 4 #include <algorithm> 5 #include <queue> 6 #include <vector> 7 #include <map> 8 #include <cstdlib> 9 #include <cstring> 10 #include <cmath> 11 typedef long long ll; 12 const int INF=0x3f3f3f3f; 13 using namespace std; 14 int n,m,a[1000][2],b[1100],c[1000][2],k,ans; 15 void dfs(int t) 16 { 17 if(t==k+1) 18 { 19 int cnt=0; 20 for(int i=1;i<=m;++i) 21 { 22 if(b[a[i][0]]&&b[a[i][1]])cnt++; 23 } 24 ans=max(cnt,ans); 25 } 26 else 27 { 28 b[c[t][0]]++; 29 dfs(t+1); 30 b[c[t][0]]--; 31 b[c[t][1]]++; 32 dfs(t+1); 33 b[c[t][1]]--; 34 } 35 } 36 int main(void) 37 { 38 cin>>n>>m; 39 for(int i=1;i<=m;++i) 40 { 41 cin>>a[i][0]>>a[i][1]; 42 } 43 cin>>k; 44 for(int i=1;i<=k;++i) 45 { 46 cin>>c[i][0]>>c[i][1]; 47 } 48 dfs(1); 49 cout<<ans<<endl; 50 return 0; 51 }
D:
给定一个整数N,求有多少个公差为1的等差数列,使得数列和为N。
分析:我们只需考虑数列为正整数的情况,然后乘2即可。因为对于任意一个满足条件的正整数数列a1,a2,……,an,都可以在前面添加一个首项为-a1+1,末项为a1-1的等差数列,使得和仍为N。假设项数为i,那么有(1+i)*i<=2*N。我们枚举每个项数,判断是否合法。
(1)若i为奇数,仅需判断N是否整除i。
(2)若i为偶数:如果N为奇数,那么i不能为4的倍数;如果N为偶数,那么i应为4的倍数。同时对任意N,还要满足N整除i/2,而且N/(i/2)为奇数。
1 #include <iostream> 2 #include <cstdio> 3 #include <vector> 4 #include <algorithm> 5 #include <queue> 6 #include <vector> 7 #include <map> 8 #include <cstdlib> 9 #include <cstring> 10 #include <cmath> 11 #include <set> 12 #include <unordered_set> 13 typedef long long ll; 14 const int INF=0x3f3f3f3f; 15 using namespace std; 16 ll n,ans; 17 int main(void) 18 { 19 cin>>n; 20 for(ll i=1;i*i+i<=2*n;++i) 21 { 22 if(i&1) 23 { 24 if(n%i==0)ans+=2; 25 } 26 else 27 { 28 if(n%2==1&&i%4!=0&&n%(i/2)==0&&(n/(i/2))%2==1||n%2==0&&i%4==0&&n%(i/2)==0&&(n/(i/2))%2==1)ans+=2; 29 } 30 } 31 cout<<ans<<endl; 32 return 0; 33 }
E:
有N种宝石和M对组合,表示第Ai和Bi种宝石可以相邻。其他的不能相邻。给出K种需要的宝石,分别为C1,C2,……,Ck,是否存在一个序列满足K种宝石都出现一次及以上,若有输出需要的最小宝石数量。
分析:设dis[i][j]表示i和Cj的最小距离(可以通过对每种需要的宝石进行一次BFS求出),dp[i][state]表示以Ci结尾的状态为state时所需要的最少宝石数(例如state为101,表示序列中有C1和C3)。那么dp[i][state]=min(dp[j][state']+dis[Cj][i]),最终答案为min(dp[i][(1<<K)-1],0<=i<K)。
1 #include <iostream> 2 #include <cstdio> 3 #include <vector> 4 #include <algorithm> 5 #include <queue> 6 #include <vector> 7 #include <map> 8 #include <cstdlib> 9 #include <cstring> 10 #include <cmath> 11 #include <set> 12 typedef long long ll; 13 const int INF=0x3f3f3f3f; 14 using namespace std; 15 int n,m,k,dis[110000][18],arr[18]; 16 int dp[18][(1<<18)]; 17 vector<int>e[110000]; 18 void bfs(int t) 19 { 20 for(int i=1;i<=n;++i)dis[i][t]=INF; 21 queue<int>que; 22 que.push(arr[t]); 23 dis[arr[t]][t]=0; 24 while(!que.empty()) 25 { 26 int p=que.front(); 27 que.pop(); 28 for(int i=0;i<e[p].size();++i) 29 { 30 int v=e[p][i]; 31 if(dis[v][t]==INF) 32 { 33 dis[v][t]=dis[p][t]+1; 34 que.push(v); 35 } 36 } 37 } 38 } 39 int solve(int last,int t) 40 { 41 if(t==((1<<k)-1))return 0; 42 int &ret=dp[last][t]; 43 if(ret!=-1)return ret; 44 ret=INF; 45 for(int i=0;i<k;++i) 46 { 47 if(t&(1<<i))continue; 48 ret=min(ret,solve(i,t|(1<<i))+dis[arr[last]][i]); 49 } 50 return ret; 51 } 52 int main(void) 53 { 54 memset(dp,-1,sizeof(dp)); 55 cin>>n>>m; 56 for(int i=0;i<m;++i) 57 { 58 int u,v; 59 cin>>u>>v; 60 e[u].push_back(v); 61 e[v].push_back(u); 62 } 63 cin>>k; 64 for(int i=0;i<k;++i)cin>>arr[i]; 65 for(int i=0;i<k;++i)bfs(i); 66 for(int i=0;i<k;++i) 67 { 68 if(dis[arr[0]][i]==INF) 69 { 70 cout<<"-1"<<endl; 71 return 0; 72 } 73 } 74 int ans=INF; 75 for(int i=0;i<k;++i) 76 { 77 ans=min(ans,1+solve(i,(1<<i))); 78 } 79 cout<<ans<<endl; 80 return 0; 81 }
F:
给出0到N-1的一组排列,将排列向左移位k次,k=0,1,……,N-1,求每次移位后的排列的逆序对数。
分析:我们先算出刚开始的排列的逆序对数x0。每次移位相当于把第一个数放到末尾。对于第i次移位,假设第i-1次移位后的逆序对数为x,第一个数为a0,那么我们只需减去在第i-1次移位中a0的贡献P1,再加上在第i次移位中a0的贡献P2即可。由于这是0到N-1的排列,可以知道P1=a0(所有比他小的数),P2=N-1-a0(所有比他大的数),因此通过循环更新x0即可。
关于求逆序对,可以看一下这道题:https://www.luogu.com.cn/problem/P1908
1 #include <iostream> 2 #include <cstdio> 3 #include <vector> 4 #include <algorithm> 5 #include <queue> 6 #include <vector> 7 #include <map> 8 #include <cstdlib> 9 #include <cstring> 10 #include <cmath> 11 #include <set> 12 typedef long long ll; 13 const int INF=0x3f3f3f3f; 14 using namespace std; 15 int a[310000],b[310000],c[310000],n; 16 ll ans; 17 void msort(int h,int r) 18 { 19 if(h==r)return; 20 int mid=(h+r)/2,i=h,j=mid+1,k=h; 21 msort(h,mid); 22 msort(mid+1,r); 23 while(i<=mid&&j<=r) 24 { 25 if(a[i]<=a[j]) 26 { 27 c[k++]=a[i++]; 28 } 29 else 30 { 31 c[k++]=a[j++]; 32 ans+=mid-i+1; 33 } 34 } 35 while(i<=mid)c[k++]=a[i++]; 36 while(j<=r)c[k++]=a[j++]; 37 for(int i=h;i<=r;++i)a[i]=c[i]; 38 } 39 int main(void) 40 { 41 scanf("%d",&n); 42 for(int i=1;i<=n;++i) 43 { 44 scanf("%d",&a[i]); 45 b[i]=a[i]; 46 } 47 msort(1,n); 48 cout<<ans<<endl; 49 for(int i=1;i<n;++i) 50 { 51 ans-=b[i]; 52 ans+=n-1-b[i]; 53 cout<<ans<<endl; 54 } 55 return 0; 56 }