2024.11.27
NOIP倒计时3天
今日总结:上午机房断网比赛,下午改题,晚上重新看了看以前写过的题
1:最大跨距
这道题我是用字符串中的stl解决的,当然更加准确的是用KMP来解决,只需要记录第一个访问的位置,和最后一个访问的位置
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
// freopen("dis.in","r",stdin);
// freopen("dis.out","w",stdout);
string s,s1,s2;
getline(cin,s,',');
getline(cin,s1,',');
cin >> s2;
int l = s.find(s1);
int len = s1.length();
int r = s.rfind(s2);
if(l > r || l == -1 || r == -1) printf("-1\n");
else printf("%d\n",r - l - len);
return 0;
}
2:都市
这道题正解是贪心,只需要对原来的序列进行排序,只需要枚举第一个数字的产生数量,再判一下重就行了,考试的时候没看出来,弄不出来样例
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 310,M = N * N;
int n,m,cnt;
int sum[M],p[M],ans[N][N];
bool b[M];
void Check(int x)
{
memset(b,0,sizeof(b));
if((sum[1] + sum[2] + sum[x]) & 1) return;
p[1] = (sum[1] + sum[2] + sum[x]) / 2 - sum[x];
p[2] = sum[1]-p[1];
p[3] = sum[2] - p[1];
b[1] = b[2] = b[x] = true;
for(int i = 4,j = 3;i <= n;i ++)
{
while(j <= m && b[j]) j ++;
if(j > m) return;
p[i] = sum[j] - p[1];
b[j] = true;
for(int k = 2;k < i;k ++)
{
if (p[k] > p[i]) return;
int v = p[k] + p[i],l = lower_bound(sum + 1,sum + m + 1,v) - sum,lb = l;
if(sum[l] != v) return;
while(lb && sum[lb] == sum[l]) lb --;
lb ++;
while(lb<=m&&sum[lb]==sum[l]&&b[lb]) lb ++;
if(sum[lb] != sum[l] || b[lb]) return;
l = lb;
b[l] = true;
}
}
cnt ++;
for(int i = 1;i <= n;i ++)
ans[cnt][i] = p[i];
}
int main()
{
// freopen("city.in","r",stdin);
// freopen("city.out","w",stdout);
scanf("%d",&n);
m = n * (n - 1) / 2;
for(int i = 1;i <= m;i ++)
scanf("%d",&sum[i]);
sort(sum + 1,sum + m + 1);
for(int i = 3,j = i;i <= m;i = j)
{
Check(i);
while(j <= m && sum[j] == sum[i]) j ++;
}
printf("%d\n",cnt);
for(int a = 1;a <= cnt;a ++)
{
for(int b = 1;b <= n;b ++)
{
printf("%d",ans[a][b]);
if(b == n) printf("\n");
else printf(" ");
}
}
return 0;
}
3:最小生成树
这道题主要是依靠拓扑序来解决,但是我在考场上只想到了用并查集去维护最后两个点超时了
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod = 1e9 + 7;
const int N = 408, M = 21, S = (1 << M);
int res, n, m;
ll dp[S], ans[S][4];
int a[N], b[N];
int h[N], nxt[N], cnt, v[N], t[N];
void add(int x, int y, int z)
{
t[++cnt] = y;
v[cnt] = z;
nxt[cnt] = h[x];
h[x] = cnt;
}
void dfs(int x, int f, int y, int dis)
{
if (y == x)
{
res = dis;
return;
}
for (int i = h[x]; i; i = nxt[i])
{
if (t[i] == f)
continue;
dfs(t[i], x, y, (dis | (1 << (v[i]))));
}
}
ll ksm(ll x, ll y)
{
ll res = 1;
while (y)
{
if (y & 1)
res = res * x % mod;
x = x * x % mod;
y >>= 1;
}
return res;
}
ll jc[N + 5], inv[N + 5];
void init()
{
jc[0] = 1;
for (int i = 1; i <= N; i++)
jc[i] = jc[i - 1] * i % mod;
inv[N] = ksm(jc[N], mod - 2);
for (int i = N - 1; i >= 0; i--)
inv[i] = inv[i + 1] * (i + 1) % mod;
}
inline int read()
{
int F = 1, ANS = 0;
char C = getchar();
while (C < '0' || C > '9')
{
if (C == '-')
F = -1;
C = getchar();
}
while (C >= '0' && C <= '9')
{
ANS = ANS * 10 + C - '0';
C = getchar();
}
return F * ANS;
}
int main()
{
init();
n = read(), m = read();
for (int i = 1; i < n; i++)
{
int x = read(), y = read();
a[i] = x, b[i] = y;
add(x, y, i - 1), add(y, x, i - 1);
}
int s = (1 << (n - 1)) - 1;
for (int i = n; i <= m; i++)
{
int x = read(), y = read();
dfs(x, 0, y, 0);
// cout << res << endl;
dp[s - res]++;
}
for (int i = 0; i < n - 1; i++)
{
for (int j = (1 << (n - 1)) - 1; j >= 0; j--)
{
if (!(j & (1 << i)))
dp[j] = (dp[j] + dp[j ^ (1 << i)]) % mod;
}
}
ans[0][0] = 0, ans[0][1] = 0, ans[0][2] = 1, ans[0][3] = 0;
for (int i = 1; i <= s; i++)
{
int u = i;
ans[i][1] = __builtin_popcount(i);
ans[i][0] = ans[i][1] + m - n + 1 - dp[i];
while (u)
{
int v = (u & (-u)), w = (i ^ v);
u ^= v;
int l = dp[w] - dp[i];
ans[i][2] = (ans[i][2] + ans[w][2] * inv[ans[w][0]] % mod * jc[ans[w][0] + l] % mod) % mod;
ans[i][3] = (ans[i][3] + ans[w][3] * inv[ans[w][0] + 1] % mod * jc[ans[w][0] + l + 1] % mod) % mod;
}
ans[i][3] = (ans[i][3] + ans[i][1] * ans[i][2] % mod) % mod;
}
cout << ans[s][3];
return 0;
}
4:测试数据
这道题可以写线段树用倍增优化,我只写了一个简单的线段树,没想到用倍增去优化,主要是实在是没有想到线段树还可以用倍增法,因为线段树本质上还是一个树
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n,m,Q;
int a[N];
struct Node
{
int l,r;
}p[N];
struct SegmentTree
{
int l,r,mx,add;
}tr[4 * N];
void pushup(int u)
{
tr[u].mx = max(tr[u << 1].mx,tr[u << 1 | 1].mx);
}
void Build(int u,int l,int r)
{
if(l == r)
{
tr[u] = {l,r,a[l],0};
return;
}
tr[u] = {l,r,0,0};
int mid = (l + r) >> 1;
Build(u << 1,l,mid),Build(u << 1 | 1,mid + 1,r);
pushup(u);
}
void pushdown(int u)
{
if(tr[u].add)
{
tr[u << 1].mx = tr[u << 1 | 1].mx = tr[u << 1 | 1].add = tr[u << 1].add = tr[u].add;
tr[u].add = 0;
}
}
void Modify(int u,int l,int r,int y)
{
if(l <= tr[u].l && tr[u].r <= r)
{
tr[u].mx = tr[u].add = y;
return;
}
pushdown(u);
int mid = (tr[u].l + tr[u].r) >> 1;
if(l <= mid) Modify(u << 1,l,r,y);
if(r > mid) Modify(u << 1 | 1,l,r,y);
pushup(u);
}
int Query(int u,int l,int r)
{
if(l <= tr[u].l && tr[u].r <= r) return tr[u].mx;
pushdown(u);
int mid = (tr[u].l + tr[u].r) >> 1,res = 0;
if(l <= mid) res = max(res,Query(u << 1,l,r));
if(r > mid) res = max(res,Query(u << 1 | 1,l,r));
pushup(u);
return res;
}
int main()
{
// freopen("evaldate.in","r",stdin);
// freopen("evaldate.out","w",stdout);
scanf("%d%d%d",&n,&m,&Q);
for(int i = 1;i <= n;i ++)
scanf("%d",&a[i]);
for(int i = 1;i <= m;i ++)
scanf("%d%d",&p[i].l,&p[i].r);
Build(1,1,n);
int opt,x,y,z;
while(Q --)
{
scanf("%d%d%d",&opt,&x,&y);
if(opt == 2)
{
scanf("%d",&z);
int Max;
for(int i = x;i <= y;i ++)
{
Max = Query(1,p[i].l,p[i].r);
Modify(1,p[i].l,p[i].r,Max);
}
printf("%d\n",Query(1,z,z));
Build(1,1,n);
}
else
{
a[x] = y;
Modify(1,x,x,y);
}
}
return 0;
}
5:词链
这道题是一道欧拉回路的题目,当然也可以用并查集,这道题因为可能会出现相同的单词,所以用dfs去求欧拉路,考虑特性
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int n,ans,st;
int idx,to[N],w[N],d[N],nxt[N],head[N];
bool flag[N];
string s[N],tot[N];
void Add(int a,int b,int c)
{
idx ++;
to[idx] = b;
w[idx] = c;
d[a] ++,d[b] --;
nxt[idx] = head[a];
head[a] = idx;
}
void dfs(int u)
{
for(int i = head[u];i;i = nxt[i])
{
int j = to[i],v = w[i];
if(!flag[v])
{
flag[v] = true;
dfs(j);
ans ++;
tot[ans] = s[v];
}
}
}
int main()
{
// freopen("line.in","r",stdin);
// freopen("line.out","w".,stdout);
scanf("%d",&n);
for(int i = 1;i <= n;i ++)
cin >> s[i];
sort(s + 1,s + n + 1);
st = s[1][0] - 'a' + 1;
for(int i = n;i >= 1;i --)
{
int h = s[i][0] - 'a' + 1;
int t = s[i][s[i].size() - 1] - 'a' + 1;
Add(h,t,i);
}
for(int i = 1;i <= 26;i ++)
{
if(d[i] == 1)
{
st = i;
break;
}
}
dfs(st);
for(int i = 1;i <= n;i ++)
{
if(!flag[i])
{
printf("***");
return 0;
}
}
for(int i = ans;i > 1;i --)
cout << tot[i] << ".";
cout << tot[1] << endl;
return 0;
}