B:贪心考虑,从小的开始砍即可,排序一下。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int N = 1e5 + 5;
const int M = 1e9 + 1;
const LL Mod = 2147483647;
#define pi acos(-1)
#define INF 1e9
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO{
inline LL read(){
LL x = 0,f = 1;char c = getchar();
while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
return x*f;
}
}
using namespace FASTIO;
int a[N];
int main()
{
int n,m,t;n = read(),m = read(),t = read();
for(int i = 1;i <= n;++i) a[i] = read();
sort(a + 1,a + n + 1);
for(int i = 1;i <= n;++i) {
if(m == 0) break;
if(t >= a[i]) {
t -= a[i];
m--;
}
}
printf("%s\n",m == 0 ? "YES" : "NO");
return 0;
}
F:搜索题。
首先我们考虑没有传送门和钟离。
那就是一个很简单的最小时间的bfs。
即:用小顶堆来维护bfs到的点用的时间,每次都取最小的时间来计算。
现在考虑加入钟离和传送门,那么就是多了一个状态。
我们知道这里的传送门如果走多次那么就会导致复杂度过高。
所以我们只需要去走一次让这个传送门就达到最优。
但是又可能存在没钟离走传送门和有钟离走传送门的情况。
所以要设置两个状态,f[i][j][0] - 表示到(i,j)位置之前没有得到过钟离的最短时间。f[i][j][1] - 表示到(i,j)位置之前没有得到钟离的最短时间。
然后在bfs中对情况进行分类即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int N = 1e3 + 5;
const int M = 1e3 + 5;
const LL Mod = 1e9 + 7;
#define pi acos(-1)
#define INF 1e12
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO{
inline int read(){
int x = 0,f = 1;char c = getchar();
while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
return x*f;
}
}
using namespace FASTIO;
int n;
string a[N];
int dir[4][2] = {1,0,-1,0,0,1,0,-1},f[N][N][2];//1 - 有钟离,0 - 没有
int sx,sy,ex,ey,ans = 0;
vector<pii> vec;
struct Node{
int x,y,step,zl;
bool operator < (const Node a) const{
return step > a.step;
}
};
void bfs() {
priority_queue<Node> Q;
f[sx][sy][0] = 0;
Q.push(Node{sx,sy,0,0});
while(!Q.empty()) {
Node q = Q.top();
Q.pop();
if(q.x == ex && q.y == ey) ans = 1;
for(int i = 0;i < 4;++i) {
int px = q.x + dir[i][0];
int py = q.y + dir[i][1];
int id = q.zl;
if(px >= 0 && px < n && py >= 0 && py < n && a[px][py] != '1') {
if(id == 1) {
if(q.step + 1 >= f[px][py][id]) continue;
f[px][py][id] = q.step + 1;
if(a[px][py] == 'X') {
for(auto v : vec) {
if(f[v.first][v.second][id] <= q.step + 1) continue;
f[v.first][v.second][id] = q.step + 1;
Q.push(Node{v.first,v.second,q.step + 1,id});
}
}
else Q.push(Node{px,py,q.step + 1,id});
}
else {
if(a[px][py] == '3') {
f[px][py][id] = q.step + 1;
Q.push(Node{px,py,q.step + 1,1});
}
else {
int tim = 1;
if(a[px][py] == '2') tim += 3;
if(f[px][py][id] <= q.step + tim) continue;
f[px][py][id] = q.step + tim;
if(a[px][py] == 'X') {
for(auto v : vec) {
if(f[v.first][v.second][id] <= q.step + tim) continue;
f[v.first][v.second][id] = q.step + tim;
Q.push(Node{v.first,v.second,q.step + tim,id});
}
}
else Q.push(Node{px,py,q.step + tim,id});
}
}
}
}
}
}
int main()
{
n = read();
for(int i = 0;i < n;++i) cin >> a[i];
memset(f,0x3f3f3f3f,sizeof(f));
for(int i = 0;i < n;++i) {
for(int j = 0;j < n;++j) {
if(a[i][j] == 'S') sx = i,sy = j;
else if(a[i][j] == 'E') ex = i,ey = j;
else if(a[i][j] == 'X') vec.push_back(pii(i,j));
}
}
bfs();
if(ans == 1) printf("%d\n",min(f[ex][ey][0],f[ex][ey][1]));
else printf("mabu kule\n");
// system("pause");
return 0;
}
C题:这题数据好像有点问题,所以就先删了。
比赛的时候看了下大家的做法,过于暴力,是会TLE的。
这题的正解:建立一棵线段树,每个节点上位置犯罪值的最大位置和最小位置,然后去查询比他大的值里的位置的最大和最小值。
这里就是区间查询,复杂度就是nlogn。
G:树的重心求最远距离
// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> pii;
const int N = 1e5 + 5;
const int M = 1e3 + 5;
const double eps = 1e-10;
const LL Mod = 998244353;
#define pi acos(-1)
#define INF 1e18
#define dbg(ax) cout << "now this num is " << ax << endl;
inline int read() {
int f = 1;LL x = 0;char c = getchar();
while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
return x*f;
}
inline long long ADD(long long x,long long y) {return (x + y) % Mod;}
inline long long DEC(long long x,long long y) {return (x - y + Mod) % Mod;}
inline long long MUL(long long x,long long y) {return x * y % Mod;}
int n,dp[N],dp2[N],a[N];
vector<int> G[N];
void dfs(int u,int fa) {
dp[u] = dp[fa] + 1;
for(auto v : G[u]) {
if(v == fa) continue;
dfs(v,u);
}
}
void dfs2(int u,int fa) {
dp2[u] = dp2[fa] + 1;
for(auto v : G[u]) {
if(v == fa) continue;
dfs2(v,u);
}
}
void solve() {
n = read();
for(int i = 1;i < n;++i) {
int x,y;x = read(),y = read();
G[x].push_back(y);
G[y].push_back(x);
}
for(int i = 1;i <= n;++i) a[i] = read();
dfs(1,0);
int mx = -1,pos1 = 0,pos2 = 0;
for(int i = 1;i <= n;++i) {
if(dp[i] > mx) mx = dp[i],pos1 = i;
}
memset(dp,0,sizeof(dp));
dp[0] = -1;
dfs(pos1,0);
mx = -1;
for(int i = 1;i <= n;++i) {
if(dp[i] > mx) mx = dp[i],pos2 = i;
}
dp2[0] = -1;
dfs2(pos2,0);
LL ans = 0;
for(int i = 1;i <= n;++i) ans = max(ans,1LL * max(dp[i],dp2[i]) * a[i]);
printf("%lld\n",ans);
}
int main() {
//freopen("data3.in","r",stdin);
//freopen("data3.out","w",stdout);
solve();
//system("pause");
return 0;
}
D:这题大家都对逆元的理解不是很够。
对概率对1e9 + 7取模其实就是一个逆元。
解法:我们需要进行拓扑排序,处理出精灵1进化到每个精灵的概率。
这里可能有一些精灵不能由1进化到,但是会进化到精灵1能进化到的某些精灵。如果把这些精灵都处理进去,那就是导致概率不正确。
所以我们需要把精灵1能进化到精灵都先dfs一次标记出来。
然后再重新构建一副拓扑图,再进行拓扑排序即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int N = 1e5 + 5;
const int M = 1e3 + 5;
const LL Mod = 1e9 + 7;
#define pi acos(-1)
#define INF 1e12
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO{
inline int read(){
int x = 0,f = 1;char c = getchar();
while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
return x*f;
}
}
using namespace FASTIO;
int n,m,in[N];
vector<int> G[N],RG[N];
map<pii,int> mp;
bool vis[N];
LL ans[N];
LL quick_mi(LL a,LL b) {
LL re = 1;
while(b) {
if(b & 1) re = re * a % Mod;
a = a * a % Mod;
b >>= 1;
}
return re;
}
void dfs(int x) {
vis[x] = 1;
if(x == n) return ;
for(auto v : G[x]) {
if(vis[v]) continue;
dfs(v);
}
}
int main()
{
n = read(),m = read();
while(m--) {
int x,y;x = read(),y = read();
if(mp[pii(x,y)]) continue;
G[x].push_back(y);
RG[y].push_back(x);
mp[pii(x,y)] = 1;
}
dfs(1);
for(int i = 1;i <= n;++i) {
for(auto v : RG[i]) {
if(!vis[v]) continue;
in[i]++;
}
}
queue<int> Q;
Q.push(1);
ans[1] = 1;
while(!Q.empty()) {
int u = Q.front();
Q.pop();
for(auto v : G[u]) {
in[v]--;
ans[v] = (ans[v] + ans[u] * quick_mi(G[u].size(),Mod - 2) % Mod) % Mod;
if(in[v] == 0) Q.push(v);
}
}
printf("%lld\n",ans[n]);
return 0;
}
H:
设事件A为x1!=x2 ,事件B 为x2!=x3 ,事件C 为 x3!=x4 事件D 为 x4!=x1
问题要求:|A∩B∩C∩D|
可以转换成|U|-|A’∪B’∪C’∪D’|
即求 |A’∪B’∪C’∪D’| 就行,容斥定理。
#include <bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
typedef long long ll;
ll Query(ll l1,ll r1,ll l2,ll r2)
{
ll l=max(l1,l2),r=min(r1,r2);
return r-l+1>0?r-l+1:0;
}
ll Query2(ll l1,ll r1,ll l2,ll r2,ll l3,ll r3)
{
ll l=max(l1,max(l2,l3)),r=min(r1,min(r2,r3));
return r-l+1>0?r-l+1:0;
}
ll Query3(ll l1,ll r1,ll l2,ll r2,ll l3,ll r3,ll l4,ll r4)
{
ll l=max(max(l1,l2),max(l3,l4)),r=min(min(r1,r2),min(r3,r4));
return r-l+1>0?r-l+1:0;
}
int main()
{
int t;
ll l1,r1,l2,r2,l3,r3,l4,r4;
scanf("%d",&t);
while(t--)
{
scanf("%lld%lld%lld%lld%lld%lld%lld%lld",&l1,&r1,&l2,&r2,&l3,&r3,&l4,&r4);
ll sum=1;
sum=sum*(r1-l1+1)%mod;
sum=sum*(r2-l2+1)%mod;
sum=sum*(r3-l3+1)%mod;
sum=sum*(r4-l4+1)%mod;
ll ant=0;
ant=(ant+Query(l1,r1,l2,r2)%mod*(r3-l3+1)%mod*(r4-l4+1)%mod)%mod;
ant=(ant+Query(l2,r2,l3,r3)%mod*(r1-l1+1)%mod*(r4-l4+1)%mod)%mod;
ant=(ant+Query(l3,r3,l4,r4)%mod*(r1-l1+1)%mod*(r2-l2+1)%mod)%mod;
ant=(ant+Query(l4,r4,l1,r1)%mod*(r3-l3+1)%mod*(r2-l2+1)%mod)%mod;
ant=(ant-Query2(l1,r1,l2,r2,l3,r3)*(r4-l4+1)%mod+mod)%mod;
ant=(ant-Query(l1,r1,l2,r2)*Query(l3,r3,l4,r4)%mod+mod)%mod;
ant=(ant-Query2(l1,r1,l2,r2,l4,r4)*(r3-l3+1)%mod+mod)%mod;
ant=(ant-Query2(l2,r2,l3,r3,l4,r4)*(r1-l1+1)%mod+mod)%mod;
ant=(ant-Query(l2,r2,l3,r3)*Query(l1,r1,l4,r4)%mod+mod)%mod;
ant=(ant-Query2(l1,r1,l3,r3,l4,r4)*(r2-l2+1)%mod+mod)%mod;
ant=(ant+3*Query3(l1,r1,l2,r2,l3,r3,l4,r4)%mod+mod)%mod;
printf("%lld\n",(sum-ant+mod)%mod);
}
return 0;
}
E:这题其实也不是特别难。
首先,我们去二分箱子的数量,这样去保证箱子尽可能少。
同时为了让最大的箱子尽可能小,我们再去二分最大的箱子的容量。
然后去判断是否能装下的时候,我们先排序,然后把大的装进去。
尽量把小的装到大的里面,扩大可以利用的空间,然后这样去判断能不能装下。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int N = 1e5 + 5;
const int M = 1e3 + 5;
const LL Mod = 1e9 + 7;
#define pi acos(-1)
#define INF 1e12
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO{
inline int read(){
int x = 0,f = 1;char c = getchar();
while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
return x*f;
}
}
using namespace FASTIO;
int a[N],ans,n,k,num;
bool solve(int m,int x) {
priority_queue<int,vector<int>,less<int> > Q;
for(int i = n;i >= n - m + 1;--i) {
Q.push(a[i]);
}
int num = 0;
int L = 1,r = n - m;
while(!Q.empty()) {
if(L > r) break;
int u = Q.top();
Q.pop();
if(a[L] + u > x) continue;
Q.push(a[L++] + u);
}
return L > r;
}
bool check(int x) {
int L = 1,r = k,ma = 0;
while(L <= r) {
int mid = (L + r) >> 1;
if(solve(x,mid)) ma = mid,r = mid - 1;
else L = mid + 1;
}
if(ma != 0) ans = ma;
return ma != 0;
}
int main()
{
n = read(),k = read();
for(int i = 1;i <= n;++i) a[i] = read();
sort(a + 1,a + n + 1);
int L = 1,r = n;
while(L <= r) {
int mid = (L + r) >> 1;
if(check(mid)) num = mid,r = mid - 1;
else L = mid + 1;
}
printf("%d %d\n",num,ans);
system("pause");
return 0;
}
A:本场防AK题,出题的时候怕被AK了,就把这个题的难度上升了。
设dp[i][j][k] - 表示到树i,j,k这个状态下能砍到的最多的树。
j = 0 表示不砍倒,j = 1 表示向左砍倒,j = 2 表示向右砍到。
k = 0 表示从左边开始的dp,k = 1表示从右边开始的dp。
如果这题不能使用魔法,那么我们只需要从左边开始dp然后取最大值即为答案。
dp的时候只需要去判断会不会重叠的问题即可。
但是这题多了一个可以删去树的操作。
那么我们需要从右边开始再dp一次。
然后我们枚举删去哪棵树,然后去枚举它两边的树的砍的状态,取里面的最大值即可。
dp的转移:(从左边开始,右边同理):这里为了方便省去k那一维,因为是一样的dp思路。
dp[i][0] = max(dp[i - 1][0],dp[i - 1][1],dp[i - 1][2]) // 不砍的话就从前面的最大的状态转移。
如果可以向左砍:那么去判断i - 1的各个砍法会不会和i向左砍重叠,不会就可以从i - 1的那个砍法转移得到。
向右砍同理。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int N = 1e5 + 5;
const int M = 1e3 + 5;
const LL Mod = 1000000;
#define pi acos(-1)
#define INF 1e12
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO{
inline LL read(){
LL x = 0,f = 1;char c = getchar();
while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
return x*f;
}
}
using namespace FASTIO;
struct TA{
int x,h;
bool operator < (const TA a) const {
return x < a.x;
}
}p[N];
int dp[N][3][2],n;// - 0 - 不倒,1 - 向左倒,2 - 向右倒,0 --- 从左开始砍,1 --- 从右开始砍
int main()
{
n = read();
for(int i = 1;i <= n;++i) p[i].x = read(),p[i].h = read();
if(n == 1) printf("1\n");
else if(n == 2) printf("2\n");
else {
sort(p + 1,p + n + 1);
int ans = 0;
dp[1][0][0] = 0,dp[1][1][0] = 1;
if(p[2].x > p[1].x + p[1].h) dp[1][2][0] = 1;
else dp[1][2][0] = 0;
for(int i = 2;i <= n;++i) {
dp[i][0][0] = max(dp[i - 1][0][0],max(dp[i - 1][2][0],dp[i - 1][1][0]));
if(p[i - 1].x < p[i].x - p[i].h) {
dp[i][1][0] = max(dp[i - 1][0][0],dp[i - 1][1][0]) + 1;
if(p[i - 1].x + p[i - 1].h < p[i].x - p[i].h) dp[i][1][0] = max(dp[i][1][0],dp[i - 1][2][0] + 1);
}
else dp[i][1][0] = max(dp[i - 1][0][0],max(dp[i - 1][2][0],dp[i - 1][1][0]));
if(p[i + 1].x > p[i].x + p[i].h || i == n) {
dp[i][2][0] = max(dp[i - 1][0][0],max(dp[i - 1][2][0],dp[i - 1][1][0])) + 1;
}
else dp[i][2][0] = max(dp[i - 1][0][0],max(dp[i - 1][2][0],dp[i - 1][1][0]));
ans = max(ans,max(dp[i][0][0],max(dp[i][1][0],dp[i][2][0])));
}
dp[n][0][1] = 0,dp[n][2][1] = 1;
if(p[n - 1].x < p[n].x - p[n].h) dp[n][1][1] = 1;
else dp[n][1][1] = 0;
for(int i = n - 1;i >= 1;--i) {
dp[i][0][1] = max(dp[i + 1][0][1],max(dp[i + 1][1][1],dp[i + 1][2][1]));
if(p[i + 1].x > p[i].x + p[i].h) {
dp[i][2][1] = max(dp[i + 1][0][1],dp[i + 1][2][1]) + 1;
if(p[i + 1].x - p[i + 1].h > p[i].x + p[i].h) dp[i][2][1] = max(dp[i][2][1],dp[i + 1][1][1] + 1);
}
else dp[i][2][1] = max(dp[i + 1][0][1],max(dp[i + 1][1][1],dp[i + 1][2][1]));
if(p[i - 1].x < p[i].x - p[i].h || i == 1) {
dp[i][1][1] = max(dp[i + 1][0][1],max(dp[i + 1][1][1],dp[i + 1][2][1])) + 1;
}
else dp[i][1][1] = max(dp[i + 1][0][1],max(dp[i + 1][1][1],dp[i + 1][2][1]));
}
for(int i = 2;i < n;++i) {
int ma1 = p[i - 1].x + p[i - 1].h;
int ma2 = p[i + 1].x - p[i + 1].h;
//0 0
ans = max(ans,dp[i - 1][0][0] + dp[i + 1][0][1]);
//0 1
int ma = (ma2 <= p[i - 1].x) ? 0 : (dp[i + 1][1][1] + (ma2 <= p[i].x));
ans = max(ans,dp[i - 1][0][0] + ma);
//0 2
ans = max(ans,dp[i - 1][0][0] + dp[i + 1][2][1]);
//1 0
ans = max(ans,dp[i - 1][1][0] + dp[i + 1][0][1]);
//1 1
ma = (ma2 <= p[i - 1].x) ? 0 : (dp[i + 1][1][1] + (ma2 <= p[i].x));
ans = max(ans,dp[i - 1][1][0] + ma);
//1 2
ans = max(ans,dp[i - 1][1][0] + dp[i + 1][2][1]);
//2 0
ma = (ma1 >= p[i + 1].x) ? 0 : (dp[i - 1][2][0] + (ma1 >= p[i].x));
ans = max(ans,ma + dp[i + 1][0][1]);
//2 1
ma = (ma2 > ma1) ? (dp[i - 1][2][0] + dp[i + 1][1][1] + (ma2 <= p[i].x) + (ma1 >= p[i].x)): 0;
ans = max(ans,ma);
//2 2
ma = (ma1 >= p[i + 1].x) ? 0 : (dp[i - 1][2][0] + (ma1 >= p[i].x));
ans = max(ans,ma + dp[i + 1][2][1]);
}
printf("%d\n",ans);
}
//system("pause");
return 0;
}