2024.11.15
今日总结:
上午打了南外的比赛,下午改了前两道,第三道80分,晚上做了图论专题
1:http://www.nfls.com.cn:10611/p/P1389
这道是div2的第一题,这道题看似是一道字符串的题目,其实是一道计数题,只需要记录在所有数中选取2个和在总数量 - 2 中选剩余的所有数的选择方案数即可
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int Mod = 1e9 + 7;
const int N = 2e3 + 10;
#define x first
#define y second
int n,k;
long long u;
long long C[N][N],dp[N][N];
string s;
map<string,int> mp;
int main()
{
scanf("%d%d",&n,&k);
C[0][0] = 1;
for(int i = 1;i <= 2000;i ++)
{
C[i][0] = C[i][i] = 1;
for(int j = 1;j < i;j ++)
C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % Mod;
}
for(int i = 1;i <= n;i ++)
{
cin >> s;
sort(s.begin(),s.end());
mp[s] ++;
}
map<string,int>::iterator it;
dp[0][0] = 1;
for(it = mp.begin();it != mp.end();it ++)
{
u ++;
for(int i = 0;i <= k;i ++)
{
int t = it -> second;
dp[u][i] = dp[u - 1][i];
for(int j = 1;j <= t && j * (j - 1) / 2 <= i;j ++)
{
int pos = j * (j - 1) / 2;
dp[u][i] = (dp[u][i] + (dp[u - 1][i - pos] * C[t][j]) % Mod) % Mod;
}
}
}
printf("%lld\n",dp[u][k]);
return 0;
}
2:http://www.nfls.com.cn:10611/p/P5292
这道题是第二题,第一开始用堆优化dfs过了所有小样例,但是大样例没过,最后因为捆绑测试点,挂0了,但实际上这道题应该是首先考虑给定的要求可以转换出是相邻列之间的差值,这是用并查集合并,能合并即为可以成立,反之则不可以
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
const int INF = 0x3f3f3f3f;
int n,m,k;
int f[N];
long long Min[N],Max[N],st[N];
int Find(int x)
{
if(x == f[x]) return x;
int t = Find(f[x]);
st[x] += st[f[x]];
return f[x] = t;
}
int main()
{
freopen("zibi.in","r",stdin);
freopen("zibi.out","w",stdout);
scanf("%d%d%d",&n,&m,&k);
for(int i = 1;i <= n + m;i ++)
{
f[i] = i;
Min[i] = INF,Max[i] = -INF;
}
while(k --)
{
int r,c,a;
scanf("%d%d%d",&r,&c,&a);
c += n;
if(Find(r) == Find(c))
{
if(st[r] - st[c] != a)
{
puts("Zikai");
return 0;
}
}
else
{
st[f[c]] = st[r] - st[c] - a;
f[f[c]] = f[r];
}
}
for(int i = 1;i <= n;i ++)
Find(i),Min[f[i]] = min(Min[f[i]],st[i]);
for(int i = n + 1;i <= n + m;i ++)
Find(i),Max[f[i]] = max(Max[f[i]],st[i]);
for(int i = 1;i <= n + m;i ++)
if(Find(i) == i && Min[i] < Max[i])
{
puts("Zikai");
return 0;
}
puts("Zibi");
return 0;
}
3:http://www.nfls.com.cn:20035/contest/2083/problem/5
这道题主要是用Spfa+Dp优化,由题目可以观察出这是一个多源最短路加上Dp
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10;
const int M = 2e4 + 10;
int n,E;
int Get[N],dp[N],dis[N][N],vis[N][N],revis[N];
// dp[i]由i出发,得到的最多的饱食度
// dis[i][j]表示从i到j的最短距离
bool st[N];
queue<int> q;
int head[N],nxt[M],to[M],idx;
void Add(int a,int b)
{
++ idx;
to[idx] = b;
nxt[idx] = head[a];
head[a] = idx;
}
void Spfa(int u,int *dis,int *vis)
{
q.push(u);
dis[u] = 0;
vis[u] = 1;
while(!q.empty())
{
int t = q.front();
int val = dis[t],v;
q.pop();
revis[t] = 0;
for(int i = head[t];i;i = nxt[i])
{
if(!vis[v = to[i]] || dis[v] > val + E)
{
dis[v] = val + E;
if(!revis[v]) q.push(v);
revis[v] = vis[v] = 1;
}
}
}
}
void dfs(int u)
{
st[u] = 1;
dp[u] = Get[u];
Spfa(u,dis[u],vis[u]);
for(int i = 1;i <= n;i ++)
{
if(Get[i] > Get[u])
{
if(vis[u][i])
{
if(!dp[i]) dfs(i);
dp[u] = max(dp[u],Get[u] + dp[i] - dis[u][i]);
}
}
}
}
int main()
{
scanf("%d%d",&n,&E);
for(int i = 1;i <= n;i ++)
{
int d;
scanf("%d%d",&Get[i],&d);
while(d --)
{
int t;
scanf("%d",&t);
Add(i,t);
}
}
int Max = -1;
for(int i = 1;i <= n;i ++)
{
if(!st[i]) dfs(i);
Max = max(Max,dp[i]);
}
printf("%d\n",Max);
return 0;
}
4:http://www.nfls.com.cn:20035/contest/2083/problem/6
这道题可以用一种巧妙的方法解决,观察题目可以得知一共只能操作一次,并且可以形成环,那么只需要已知dfs路径找到路径中的最大的差值找到了结束
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
const int INF = 0x3f3f3f3f;
int n,m;
int Min[N],w[N],cost[N];
vector<int> g[N];
void dfs(int u,int minn,int pre)
{
bool st = true;
minn = min(minn,w[u]);//确定最小价值
if(Min[u] > minn) Min[u] = minn,st = false;
int maxx = max(cost[pre],w[u] - minn);
if(cost[u] < maxx) cost[u] = maxx,st = false;
if(st) return;
for(int i = 0;i < g[u].size();i ++)
dfs(g[u][i],minn,u);
}
int main()
{
scanf("%d%d",&n,&m);
memset(Min,0x3f,sizeof(Min));
for(int i = 1;i <= n;i ++)
scanf("%d",&w[i]);
for(int i = 1;i <= m;i ++)
{
int a,b,t;
scanf("%d%d%d",&a,&b,&t);
g[a].push_back(b);
if(t == 2) g[b].push_back(a);
}
dfs(1,INF,0);
printf("%d\n",cost[n]);
return 0;
}
5:http://www.nfls.com.cn:20035/contest/2083/problem/7
这道题主要考察了dfs和bitset的使用。因为bitset忘了,所以又重新学习了bitset
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int n, m, k, a[1005];
bitset<1001> b[1005];
bool vis[1005];
vector<int> con[1005];
void dfs(int u)
{
vis[u] = 1;
for (int v : con[u])
if (!vis[v])
dfs(v);
}
int main()
{
scanf("%d%d%d", &n, &m, &k);
while (m--)
{
int u, v;
scanf("%d%d", &u, &v);
con[v].push_back(u);
}
for (int i = 1; i <= k; i++)
scanf("%d", &a[i]);
for (int i = 1; i <= n; i++)
{
dfs(i);
for (int j = 1; j <= n; vis[j++] = 0)
b[i][j] = (vis[j] && !con[j].size());
}
for (int i = 1; i <= n; i++)
{
bool flag = 0;
for (int j = 1; j <= k; j++)
if ((b[i] | b[a[j]]) == b[i])
{
flag = 1;
break;
}
if (flag)
printf("%d ", i);
}
return 0;
}