A. 打怪
先求出每次打死一只怪需要掉多少血,然后就直接算出能够打死多少只。
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{IO;int T=1;cin>>T; while(T--){int h,a,H,A;cin>>h>>a>>H>>A;int cnt=(H+a-1)/a;int p=(cnt-1)*A;if(p) cout<<(h-1)/p<<'\n';else cout<<"-1\n";}return 0;
}
B. 吃水果
不妨设n<mn<mn<m,如果我们先吃kkk次然后加倍一次能够使得m=nm=nm=n那么需要满足2×(n−k)=m−k2×(n-k)=m-k2×(n−k)=m−k,得出k=2n−mk=2n-mk=2n−m,由此只需先让加倍到2n>=m2n>=m2n>=m然后吃kkk次再次加倍然后在吃m−km-km−k次即可吃完,由此上面贪心一定最小。
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{IO;int T=1;cin>>T;while(T--){int n,m;cin>>n>>m;if(n>m) swap(n,m);int res=m;while(n<m){res++;n*=2;}cout<<res<<'\n';} return 0;
}
C. 四个选项
首先先用并查集统计出每个连通块的数量,然后把每一个连通块看成一个物品,跑一边背包问题即可。
状态表示:f(i,j,k,l,r)f_{(i,j,k,l,r)}f(i,j,k,l,r)考虑前iii个物品,答案A选了jjj个,答案B选了kkk个,答案C选了lll个,答案D选了rrr个的集合。
状态转移:考虑第iii个物品放在哪个答案中不难写出转移。
感觉这方法有点暴力,但是思路应该还是非常好理解
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=15;
int p[N],sz[N];
ll f[N][N][N][N][N];
int find(int x)
{return x==p[x]?x:p[x]=find(p[x]);
}
int main()
{IO;int T=1;//cin>>T;while(T--){for(int i=1;i<=12;i++) p[i]=i,sz[i]=1;int a,b,c,d,m;cin>>a>>b>>c>>d>>m;vector<int> v;v.push_back(0);while(m--){int a,b;cin>>a>>b;int pa=find(a),pb=find(b);if(pa==pb) continue;sz[pb]+=sz[pa];p[pa]=pb;}for(int i=1;i<=12;i++) if(p[i]==i) v.push_back(sz[i]);f[0][0][0][0][0]=1;int n=v.size()-1;for(int i=1;i<=n;i++)for(int j=0;j<=a;j++)for(int k=0;k<=b;k++) for(int l=0;l<=c;l++)for(int r=0;r<=d;r++){if(j>=v[i]) f[i][j][k][l][r]+=f[i-1][j-v[i]][k][l][r];if(k>=v[i]) f[i][j][k][l][r]+=f[i-1][j][k-v[i]][l][r];if(l>=v[i]) f[i][j][k][l][r]+=f[i-1][j][k][l-v[i]][r];if(r>=v[i]) f[i][j][k][l][r]+=f[i-1][j][k][l][r-v[i]];}cout<<f[n][a][b][c][d]<<'\n';}return 0;
}
D.最短路变短了
原图跑一边dijsktra算出dist1[i]
表示1~i
的最短距离,在跑一边反图算出dist2[i]
表示i~n
的最短距离。
考虑如果u→vu\to vu→v之间的边取反能够缩短1→n1\to n1→n的最短距离,那么说明目前最短路径一定是1→⋯→v→u→⋯→n1\to \dots \to v\to u\to \dots \to n1→⋯→v→u→⋯→n,因此只需要判断该条件是否成立即可得到答案(dist1[v]+dist2[u]+c<dist1[n]
)
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef pair<ll,int> pli;
const int N=100010,M=400010;
int h1[N],h2[N],e[M],ne[M],idx;
ll w[M];
ll dist1[N],dist2[N];
bool st[N];
struct node
{int u,v;ll w;
}E[M];
int n,m,q;
void add(int h[],int a,int b,ll c)
{e[idx]=b;ne[idx]=h[a];w[idx]=c;h[a]=idx++;
}
void dijkstra(int start,int h[],ll dist[])
{memset(dist,0x3f,8*N);memset(st,0,sizeof st);priority_queue<pli,vector<pli>,greater<pli> >q;dist[start]=0;q.push({0,start});while(q.size()){int t=q.top().second;q.pop();if(st[t]) continue;st[t]=1;for(int i=h[t];i!=-1;i=ne[i]){int j=e[i];if(dist[j]>dist[t]+w[i]){dist[j]=dist[t]+w[i];q.push({dist[j],j});}}}
}
int main()
{IO;int T=1;//cin>>T;while(T--){memset(h1,-1,sizeof h1);memset(h2,-1,sizeof h2);cin>>n>>m;for(int i=1;i<=m;i++){cin>>E[i].u>>E[i].v>>E[i].w;add(h1,E[i].u,E[i].v,E[i].w);add(h2,E[i].v,E[i].u,E[i].w);}dijkstra(1,h1,dist1);dijkstra(n,h2,dist2);cin>>q;while(q--){int id;cin>>id;int u=E[id].u,v=E[id].v,c=E[id].w;if(dist1[n]>dist1[v]+dist2[u]+c) cout<<"YES\n";else cout<<"NO\n";}}return 0;
}
E.相似的子串
字符串哈希+二分
二分扫一遍序列即可,用哈希表记录出现次数已经最后一次出现的位置。
时间复杂度O(nlogn)O(nlogn)O(nlogn)
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
#include<unordered_map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
const int N=200010,P=131;
unordered_map<ull,pii> mp;
ull h[N],p[N];
int n,k;
char s[N];
ull get(int l,int r)
{return h[r]-h[l-1]*p[r-l+1];
}
bool check(int mid)
{mp.clear();for(int i=mid;i<=n;i++){ull v=get(i-mid+1,i);if(mp[v].second<=i-mid) {mp[v].first++;mp[v].second=i;if(mp[v].first>=k) return 1;}}return 0;
}
int main()
{IO;int T=1;//cin>>T;while(T--){cin>>n>>k;cin>>s+1;p[0]=1;for(int i=1;i<=n;i++){p[i]=p[i-1]*P;h[i]=h[i-1]*P+s[i]-'a'+1;}int l=0,r=n;while(l<r){int mid=l+r+1>>1;if(check(mid)) l=mid;else r=mid-1;}cout<<l<<'\n';}return 0;
}
F.苹果树
点分治?待补?