A. Accumulation of Dominoes
签到,数砖块
#include<bits/stdc++.h>
#define int long long
using namespace std;
signed main()
{
int n,m;cin>>n>>m;
if(m==1)cout<<n-1<<endl;
else cout<<n*(m-1)<<endl;
return 0;
}
B. Basketball Together
题意:p数组是每个人的战力,每个队的战力是人数*队里的最高战力
敌队的战力是D,求能够组多少队
思路:
1.把战力从小到大排序,l 是左箭头,r 是右箭头。
2.将r作为最高战力时,l 消耗的人数是D/ p[r] 。
3.如果 l 加上消耗人数大于 r ,那么break。
代码:
#include<bits/stdc++.h>
using namespace std;
int p[100005];int n,d;
int main()
{
cin>>n>>d;
for(int i=0;i<n;i++)cin>>p[i];
sort(p,p+n);
int l=0,r=n-1;int ans=0;
for(r=n-1;r>=l;r--){
if(l+d/p[r]<=r){ans++;l+=d/p[r];}
else break;
}
cout<<ans<<'\n';
return 0;
}
G. Garage
题意:三角形一条直角边是a,一条斜边是b,求第n小的。
思路:
当b=a+1时,x=2*a+1,除了1之外的所有奇数都是符合的x
当b=a+2时,x=4*a+4,除了4之外的所有4的倍数都是符合的x
简单枚举一下
3 5 7
8 9 11
12 13 15……
那么可以直接列出公式解。
代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;cin>>n;
if(n==1)cout<<3;
else if(n%3==1)cout<<4*(n/3+1);
else if(n%3==2)cout<<4*(n/3+1)+1;
else if(n%3==0)cout<<4*(n/3)+3;
return 0;
}
H. Hot Black Hot White
简单的找规律
已知按照计算规则有:
// x y result
// 1 1 2
// 1 0 1
// 1 2 2
// 0 2 1
// 0 0 0
// 2 2 2
所以如果num0>=num1+num2,那么Z=2,优先01和02,剩下00。
否则 Z=0,只要不让0和0在一起就可以了
代码:【虽然代码有点长,但都是重复的段落】
#include<bits/stdc++.h>
using namespace std;
int a[100005];
stack<int>v[3];
int main()
{
char s[100005];
int n;cin>>n;int x,y; s[n]='\0';
for(int i=0;i<n;i++){cin>>a[i];v[a[i]%3].push(i);}
if(v[0].size()>=v[1].size()+v[2].size()){
cout<<2<<endl;
while(!v[1].empty()){
x=v[1].top();y=v[0].top();
v[1].pop();v[0].pop();
s[x]='1';s[y]='0';
}
while(!v[2].empty()){
x=v[2].top();y=v[0].top();
v[2].pop();v[0].pop();
s[x]='1';s[y]='0';
}
while(!v[0].empty()){
x=v[0].top();v[0].pop();y=v[0].top();v[0].pop();
s[x]='1';s[y]='0';
}
}
else{
cout<<0<<endl;
while(!v[0].empty()){
if(!v[2].empty()){
x=v[0].top();v[0].pop();y=v[2].top();v[2].pop();
s[x]='1';s[y]='0';
}
else if(!v[1].empty()){
x=v[0].top();v[0].pop();y=v[1].top();v[1].pop();
s[x]='1';s[y]='0';
}
}
while(!v[1].empty()){
if(!v[2].empty()){
x=v[1].top();v[1].pop();y=v[2].top();v[2].pop();
s[x]='1';s[y]='0';
}
else if(!v[1].empty()){
x=v[1].top();v[1].pop();y=v[1].top();v[1].pop();
s[x]='1';s[y]='0';
}
}
while(!v[2].empty()){
if(!v[1].empty()){
x=v[2].top();v[2].pop();y=v[1].top();v[1].pop();
s[x]='1';s[y]='0';
}
else if(!v[2].empty()){
x=v[2].top();v[2].pop();y=v[2].top();v[2].pop();
s[x]='1';s[y]='0';
}
}
}
cout<<s<<endl;
return 0;
}
M. Moving Both Hands
题意:找到从1和k走到相同节点的最少花费
思路:
1. 最少花费是 dis(1 , v) + dis(k , v) 【其中v是1~n的任意一个数】
2.设有向图都反向,dis'(v , k)= dis(k , v)
3.所以最少花费是dis(1,v)+dis'(v , k)
4.因为正向图和反向图接在一起了,所以dis''(1,k)=dis(1,v)+dis'(v , k)
直接dijstra就可以了
dijstra首先找到连接u的所有边,更新u到v的所有距离,并且把他们都放到heap里面按 花费 排序。之后取排序中花费最小的那个点x,找到连接x的所有vx,更新 通过点x 能使 vx到点u最短,更新之后再放到堆排序中
尽管 i 和 i+n 之间的距离是0,但是 dis[i] 和 dis[i+n] 都可能是答案,可能因为 i 和 1先更新,那么之后遇到 i+n 更新后,想要在更新 i 就发现 i 已经更新过了,所以答案就在dis[i+n]里面而不在dis[i]里面。所以在最终求答案的时候找最小值。
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define inf 0x3f3f3f3f3f3f3f3f
typedef pair<long long,long long> pll;
int dis[400005],vis[400005];int n,m;
vector<pll>mp[400005];
void dijkstra(int u)
{
for(int i=2;i<=2*n;i++)dis[i]=inf; memset(vis,0,sizeof vis);dis[u]=0;
priority_queue<pll, vector<pll>,greater<pll> >heap;
heap.push({0,u});
while (heap.size()){
pll t = heap.top();heap.pop();
int ver = t.second;if (vis[ver]) continue;vis[ver]=true;
for(auto k:mp[ver]){
if(!vis[k.second]&&dis[k.second]>dis[ver]+k.first){
dis[k.second]=dis[ver]+k.first;
heap.push({dis[k.second],k.second});
}
}
}
}
signed main()
{
cin>>n>>m;
for(int i=1;i<=n;i++){mp[i].push_back({0,i+n});}
for(int i=0;i<m;i++){
int u,v,w;cin>>u>>v>>w;
mp[u].push_back({w,v});
mp[v+n].push_back({w,u+n});
}
dijkstra(1);
for(int i=2;i<=n;i++){
if(dis[i]!=inf||dis[i+n]!=inf)cout<< min(dis[i],dis[i+n])<<' ';
else cout<<-1<<' ';
}
}
return 0;
}