目录
试题 A: 日期统计 .本题总分:5 分
试题 B: 01 串的熵.本题总分:5 分
试题 C: 冶炼金属.本题总分:10 分
试题 D: 飞机降落.本题总分:10 分
试题 E: 接龙数列 .本题总分:15 分
试题 F: 岛屿个数 .本题总分:15 分
试题 G: 子串简写 .本题总分:20 分
试题 H: 整数删除.本题总分:20 分
试题 I: 景区导游 .本题总分:25 分
试题 J: 砍树 .本题总分:25 分
相同的日期你只需要统计一次即可,直接dfs剪枝跑就可以了 我的答案235
二分,l=1,r=23333333>>1 ,我的答案11027421
对于最大值,可以根据整除分块定理2知道是a/b,然后取个min就是最大值,对于最小值,二分求,复杂度O(nlogn)
然后其实知道r=a/b,那么也不难推出l是前一个块的r+1,也就是l=a/(b+1)+1 复杂度O(N)
#include
using namespace std;
#define ll long long
#define endl '\n'
#define x first
#define y second
#define pd push_back
const int maxn=1e4+10;
int n;
ll a[maxn],b[maxn];
void solve()
{
cin>>n;
ll ma=-1,mi=-1;
for(int i=1;i<=n;i++)
{
cin>>a[i]>>b[i];
ll now=a[i]/b[i];
if(ma==-1||ma>now)
{
ma=now;
}
mi=max(mi,(a[i]/(b[i]+1))+1);
}
cout<>tn;
while(tn--)
{
solve();
}
return 0;
}
贪心寄了,还是全排列暴力~~~~~
还是dfs剪枝暴力吧,t<=10,n<=10
#include
using namespace std;
#define ll long long
#define endl '\n'
#define x first
#define y second
#define pd push_back
const int maxn=1e2+10;
struct node
{
int t,d,l;
} ;
int n;
node a[maxn];
int f[maxn];
int flag;
void dfs(int len,int last)
{
if(len==n)
{
flag=1;
return;
}
for(int i=1;i<=n&&!flag;i++)
{
if(f[i])continue;
auto [t,d,l]=a[i];
if(last<=t+d)
{
f[i]=1;
dfs(len+1,max(last+l,t+l));
f[i]=0;
}
}
}
void solve()
{
cin>>n;
flag=0;
for(int i=1;i<=n;i++)
{
cin>>a[i].t>>a[i].d>>a[i].l;
f[i]=0;
}
dfs(0,-1);
if(flag)cout<<"YES"<>tn;
while(tn--)
{
solve();
}
return 0;
}
考虑dp, dp[i],表示以i结尾的子序列最大长度,当前数字开头为j结尾为i,那么dp[i]=max(dp[i],dp[j]+1);,最后n-最长子序列就可以了,复杂度O(N)
#include
using namespace std;
#define ll long long
#define endl '\n'
#define x first
#define y second
#define pd push_back
const int maxn=1e5+10;
int n;
int dp[10];
/*
5
11 121 22 12 2023
1
*/
void solve()
{
cin>>n;
for(int i=1,j;i<=n;i++)
{
cin>>j;
int f=j,d=j%10;
while(f>=10)f/=10;
dp[d]=max(dp[d],dp[f]+1);
}
int ma=1;
for(int i=0;i<10;i++)
{
ma=max(ma,dp[i]);
//cout<>tn;
while(tn--)
{
solve();
}
return 0;
}
先从最外海水跑图,记录外部海水数量,岛的4周海水得有1个方向等于外部海水.否则就是环岛的子岛屿;
跑海水从8个方向染色;
然后跑周围是外部海水的岛屿,四个方向染++cnt,最后输出cnt就是答案
0(N*N)
#include
#define int int64_t
#define endl '\n'
using namespace std;
const int MAX = 55;
const int INF = 0x3f3f3f3f3f3f3f3fll;
const int MOD = 1e9 + 7;
char map_[MAX][MAX]; // 地图
bool track[MAX][MAX] = {false}; // 访问标记
bool outsea[MAX][MAX] = {false}; // 外海标记
struct XY {
int x, y;
} nxt[] = {
{1, 0},
{-1, 0},
{0, 1},
{0, -1},
{1, 1},
{-1, 1},
{1, -1},
{-1, -1},
};
void solve() {
int n, m;
cin >> n >> m;
for (int i = 0; i < n; i++) {
cin >> map_[i];
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
track[i][j] = false;
outsea[i][j] = false;
}
}
// 预处理外海
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (map_[i][j] == '1' or track[i][j]) continue;
bool yep = false;
queue que, arr;
track[i][j] = true;
que.push({i, j});
arr.push({i, j}); // 记录搜索到的所有海域
while (not que.empty()) {
XY pos = que.front();
que.pop();
// 注意:海域搜索可以往八个方向走,陆地搜索只能朝四个方向
for (int i = 0; i < 8; i++) {
XY nw = {pos.x + nxt[i].x, pos.y + nxt[i].y};
if (0 <= nw.x and nw.x < n and 0 <= nw.y and nw.y < m) {
if (map_[nw.x][nw.y] == '0' and track[nw.x][nw.y] == false) {
track[nw.x][nw.y] = true;
que.push(nw);
arr.push(nw);
}
} else {
yep = true; // 如果有一次搜索到地图外,标记此次搜索的所有区域为外海
}
}
}
if (yep) {
while (not arr.empty()) {
XY pos = arr.front();
arr.pop();
outsea[pos.x][pos.y] = true; // 标记搜索到的海域为外海
}
}
}
}
// 别忘了清空访问标记
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
track[i][j] = false;
}
}
// 处理岛屿
int cnt = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (map_[i][j] == '0' or track[i][j]) continue;
bool yep = false;
queue que;
track[i][j] = true;
que.push({i, j});
while (not que.empty()) {
XY pos = que.front();
que.pop();
for (int i = 0; i < 4; i++) {
XY nw = {pos.x + nxt[i].x, pos.y + nxt[i].y};
if (0 <= nw.x and nw.x < n and 0 <= nw.y and nw.y < m) {
if (map_[nw.x][nw.y] == '1') {
if (track[nw.x][nw.y] == false) {
track[nw.x][nw.y] = true;
que.push(nw);
}
} else {
if (outsea[nw.x][nw.y]) {
yep = true; // 搜索到外海为外岛
}
}
} else {
yep = true; // 搜索到边界外为外岛
}
}
}
if (yep) {
cnt++; // 外岛计数
}
}
}
cout << cnt << endl;
}
int32_t main() {
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(0);
int t;
cin >> t;
while (t--)
solve();
return 0;
}
把c1的位置存起来,对于每个c2位置二分找最小符合的位置,ans加上这个位置下标就可以了
也可以双指针暴力
#include
using namespace std;
#define ll long long
#define endl '\n'
#define x first
#define y second
#define pd push_back
#define pii pair
const int maxn=5e5+10;
int n,k;
char s[maxn],a,b;
/*
4
abababdb a b
4
ba a b
*/
void solve()
{
cin>>k;
cin>>s+1;
cin>>a>>b;
n=strlen(s+1);
vectorva,vb;
for(int i=1;i<=n;i++)
{
if(s[i]==a)
{
va.pd(i);
}
if(s[i]==b)
{
vb.pd(i);
}
}
va.pd(n+1);
vb.pd(n+1);
ll ans=0;
for(int i=0;ivb[i]-k+1)
{
r--;
}
ans+=r+1;
//cout<>tn;
while(tn--)
{
solve();
}
return 0;
}
线段树+并查集
对于每个点并查集维护左父亲和右父亲。对于每次操作线段树找到最左侧最小下标,然后返回,
这个点的左父亲等于这个点左边的点的左父亲,右同理,然后线段树修改值即可
复杂度 O(KlogN)
可以也采用set存点值和下标,然后+并查集
复杂度也是O(KlogN)
#include
using namespace std;
#define ll long long
#define endl '\n'
#define x first
#define y second
#define pd push_back
#define pii pair
const int maxn=5e5+10;
int n,k;
ll a[maxn];
int l[maxn],r[maxn],f[maxn];
int findl(int x)
{
return x==l[x]?x:l[x]=findl(l[x]);
}
int findr(int x)
{
return x==r[x]?x:r[x]=findr(r[x]);
}
ll tr[maxn<<4];
void up(int rt)
{
tr[rt]=min(tr[rt<<1],tr[rt<<1|1]);
}
void build(int rt,int l,int r)
{
tr[rt]=a[l];
if(l==r)return;
int mid=l+r>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
up(rt);
}
pii cha(int rt,int l,int r)
{
if(l==r)
{
return {l,tr[rt]};
}
int mid=l+r>>1;
pii ans;
if(tr[rt<<1]<=tr[rt<<1|1])
{
ans=cha(rt<<1,l,mid);
}else
{
ans=cha(rt<<1|1,mid+1,r);
}
return ans;
}
void add(int rt,int l,int r,int id,ll val)
{
if(id==l&&id==r)
{
tr[rt]+=val;
a[l]=tr[rt];
return;
}
int mid=l+r>>1;
if(l<=id&&id<=mid)add(rt<<1,l,mid,id,val);
else if(id>mid&&id<=r)add(rt<<1|1,mid+1,r,id,val);
up(rt);
}
/*
5 3
1 4 2 8 7
5 4
1 4 2 8 7
5 5
1 4 2 8 7
*/
void solve()
{
cin>>n>>k;
l[0]=0;l[n+1]=0;
r[0]=0;r[n+1]=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
l[i]=i;r[i]=i;
f[i]=1;
}
build(1,1,n);
while(k--)
{
ll mi=1e18,id=-1;
// for(int i=1;i<=n;i++)//可用线段树优化
// {
// if(mi>a[i])
// {
// mi=a[i];
// id=i;
// }
// }
pii i=cha(1,1,n);
id=i.x;mi=i.y;
f[id]=0;
l[id]=findl(l[id-1]);
r[id]=findr(r[id+1]);
if(l[id]>=1)add(1,1,n,l[id],mi);
if(r[id]<=n)add(1,1,n,r[id],mi);
add(1,1,n,id,1e17);
// a[l[id]]+=a[id];
// a[r[id]]+=a[id];
// a[id]=1e18;
// for(int i = 1; i <= n; i++)
// {
// if(f[i])
// {
// cout << a[i] << " ";
// }
// }
// cout<>tn;
while(tn--)
{
solve();
}
return 0;
}
倍增,由于要按顺序去游览点,考虑起点那么只有A1,A2,对于2-k的点都是以A1为起点,那么其实路都差不多,假设在这之中p点不去,减去p-1到p的路径值减去p到p+1的路径值,加上p-1到p+1的路径值即可
复杂度O(NlogN+KlogN)
对于加减路径值也可以用树链剖分或lct 复杂度O(NlogN+KlogN)
#include
using namespace std;
using ll = long long;
const int N = 2e5 + 10;
int h[N], e[N], w[N], ne[N], idx = 0;
int lg[N], p[N][20], deep[N], a[N];
ll dis[N], n, k, sum = 0;
void dfs(int lst, int now) {
deep[now] = deep[lst] + 1;
p[now][0] = lst;
for (int i = 1; (1 << i) <= deep[now]; i++)
p[now][i] = p[p[now][i - 1]][i - 1];
for (int i = h[now]; i; i = ne[i]) {
int to = e[i], cost = w[i];
if (to != lst) {
dis[to] = dis[now] + cost;
dfs(now, to);
}
}
}
int lca(int u, int v) {
if (deep[u] < deep[v]) swap(u, v);
while (deep[u] > deep[v])
u = p[u][lg[deep[u] - deep[v]]];
if (u == v) return u;
else {
for (int i = lg[deep[u]]; i >= 0; i--) {
if (p[u][i] != p[v][i])
u = p[u][i], v = p[v][i];
}
}
return p[u][0];
}
inline void add(int u, int v, int t) {
e[++idx] = v, w[idx] = t, ne[idx] = h[u], h[u] = idx;
}
inline ll ask(int u, int v) {
if (u == 0 || v == 0) return 0;
else return dis[u] + dis[v] - 2 * dis[lca(u, v)];
}
inline ll query(int i) {
return ask(a[i - 1], a[i + 1]) - ask(a[i - 1], a[i]) - ask(a[i], a[i + 1]);
}
int main() {
cin >> n >> k;
for (int i = 1; i < n; i++) {
int u, v, t;
cin >> u >> v >> t;
add(u, v, t);
add(v, u, t);
}
for (int i = 2; i <= n; i++)lg[i] = lg[i >> 1] + 1;
dfs(0, 1);
for (int i = 1; i <= k; i++)cin >> a[i];
for (int i = 2; i <= k; i++)sum += ask(a[i - 1], a[i]);
for (int i = 1; i <= k; i++)cout << sum + query(i) << ' ';
}
倍增+树上差分,对于一个数对,我们对数对路径上的值+1,最后看是否有一条边的左右点的点值相等
复杂度O(NlogN+N)
其实要对于数对路径值+1,也可以使用树链剖分来写,这样复杂度也是O(NlogN)
#include
using namespace std;
#define ll long long
#define endl '\n'
#define x first
#define y second
#define pd push_back
#define pii pair
const int maxn=1e5+10;
struct beizeng
{
int dp[22][maxn],deep[maxn];
int val[maxn];
vectorv[maxn];
void add(int a,int b)
{
v[a].pd(b);
v[b].pd(a);
}
void dfs(int x,int fa)
{
//dft[op]=x;
//df[x]=op++;
deep[x]=deep[fa]+1;
dp[0][x]=fa;
for(int i=1;(1<deep[b])swap(a,b);
for(int i=20;i>=0;i--)
{
if(deep[a]<=deep[b]-(1<=0;i--)
{
if(dp[i][a]!=dp[i][b])
{
a=dp[i][a];
b=dp[i][b];
}
}
return dp[0][a];
}
}tree;
int n,m;
int a[maxn],b[maxn];
void solve()
{
cin>>n>>m;
for(int i=1;i>a[i]>>b[i];
tree.add(a[i],b[i]);
}
tree.dfs(1,0);
for(int i=1;i<=m;i++)
{
int x,y;
cin>>x>>y;
int c=tree.lca(x,y);
tree.val[x]++;tree.val[y]++;
tree.val[c]--;tree.val[tree.dp[0][c]]--;
}
tree.dfs2(1,0);
int ans=-1;
for(int i=n-1;i>=1;i--)
{
if(tree.val[a[i]]==m&&tree.val[b[i]]==m)
{
ans=i;
break;
}
}
cout<>tn;
while(tn--)
{
solve();
}
return 0;
}