插松枝
这题主要恶心点在于题意属于是很难在赛时看明白,当时浪费了快一个小时,之后仔细捋了一下思路发现也就是stl,需要注意的就是卡格式以及各种情况不要漏。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<stack>
#include<deque>
#include<vector>
using namespace std;
const int N = 1e3 + 10;
deque<int> p;
stack<int> hezi;
vector<int> ans[N];
int n, m, k;
int getb(int temp, int num)
{
int t = 0;
if (hezi.size())
{
t = hezi.top();
if (t > num)
{
if (!p.size()) return -1;
else
{
while (p.size())
{
auto t = p.front();
p.pop_front();
if (t <= num)
{
return t;
}
else
{
//cout << t << "tnum " << num << endl;
if (hezi.size() == m)
{
p.push_front(t);
return -1;
}
else hezi.push(t);
}
}
}
}
else
{
hezi.pop();
return t;
}
}
else
{
while (p.size())
{
auto t = p.front();
p.pop_front();
if (t <= num)
{
return t;
}
else
{
//cout << t << "tnum " << num << endl;
if (hezi.size() == m)
{
p.push_front(t);
return -1;
}
else hezi.push(t);
}
}
return t;
}
return -2;
}
void solve()
{
cin >> n >> m >> k;
int temp = 0;
for (int i = 1; i <= n; i++)
{
int num;
cin >> num;
p.push_back(num);
}
while (p.size()|| hezi.size())
{
int t = 0;
if (ans[temp].size() == 0)
{
t = getb(temp, 110);
if (t == -1)
{
temp++;
continue;
}
else if(t==-2) continue;
ans[temp].push_back(t);
}
else if (ans[temp].size() == k)
{
temp++;
}
else
{
int len = ans[temp].size();
t = getb(temp, ans[temp][len - 1]);
//cout << "ans" << ans[temp][len - 1] << endl;
if (t == -1)
{
temp++;
continue;
}
else if(t==-2) continue;
ans[temp].push_back(t);
}
//cout << temp << "temp" << t << "t" << hezi.size() << "盒子";
//for (auto x : ans[temp]) cout << x << " ";
//puts("");
}
for (int i = 0; i < temp; i++)
{
for (int j = 0; j < ans[i].size(); j++)
{
if (j == ans[i].size() - 1) cout << ans[i][j];
else cout << ans[i][j] << " ";
}
puts("");
}
if (ans[temp].size())
{
for (int j = 0; j < ans[temp].size(); j++)
{
if (j == ans[temp].size() - 1) cout << ans[temp][j];
else cout << ans[temp][j] << " ";
}
}
}
int main()
{
solve();
}
老板的作息表
算上0点和24点输出首位不连续的时间段就可以
#include <bits/stdc++.h>
using namespace std;
int n;
vector<pair<string,string>> q;
int main(){
cin >> n;
while(n -- ){
string a, b, c;
cin >> a >> b >> c;
q.push_back({a, c});
}
q.push_back({"", "00:00:00"});
q.push_back({"23:59:59", ""});
sort(q.begin(), q.end());
int m = q.size();
for (int i = 0; i < m - 1; i ++ )
if (q[i].second != q[i + 1].first)
cout << q[i].second << " - " << q[i + 1].first << endl;
return 0;
}
龙龙送外卖
对于每个点从根部开始从下往上搜,记录深度,只要搜到我曾经搜过的点的位置,就可以停止,表示这是一段新路径,最后减去当时可以走的最长路径,也就是其他路径来回走两遍,最长路径只走一遍。
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1e5 + 10;
int dep[N], fa[N];
int n, m, beg, ans, maxn;
int dfs(int a,int l)
{
if (a == beg || dep[a] != 0)
{
return l * 2;
}
int p = dfs(fa[a], l + 1);
dep[a] = dep[fa[a]] + 1;
return p;
}
void solve()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
cin >> fa[i];
if (fa[i] == -1) beg = i;
}
while (m--)
{
int s;
cin >> s;
ans += dfs(s, 0);
maxn = max(maxn, dep[s]);
cout << ans - maxn << endl;
}
}
int main()
{
solve();
}
大众情人
距离感是可以传递的,这题目的是要我们判断所有点的距离感找到之中的大众情人,所以考虑弗洛伊德
o(n3)N<500,可行。查找是还需要考虑性别,男对女和女对男都需要找,因为可以重复,还需要排序,这里用了map。
#include<iostream>
#include<cstring>
#include<vector>
#include<cstring>
#include<map>
using namespace std;
const int N = 520;
int g[N][N], n;
bool sex[N];
map<int, vector<int>> ansboy, ansgirl;
void solve()
{
cin >> n;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
{
if (i == j) g[i][j] = 0;
else g[i][j] = 0x3f3f3f3f;
}
for (int i = 1; i <= n; i++)
{
char s;
int num;
cin >> s >> num;
if (s == 'M') sex[i] = 1;
while (num--)
{
int a, b;
scanf("%d:%d", &a, &b);
g[i][a] = min(g[i][a], b);
}
}
for (int k = 1; k <= n; k++)
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
{
g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
}
for (int i = 1; i <= n; i++)
{
int res = 0;
if (sex[i])
{
for (int j = 1; j <= n; j++)
{
if (i == j || sex[j]) continue;
res = max(res, g[j][i]);
}
ansboy[res].push_back(i);
}
else
{
for (int j = 1; j <= n; j++)
{
if (i == j || sex[j] == 0) continue;
res = max(res, g[j][i]);
}
ansgirl[res].push_back(i);
}
}
for (auto x : ansgirl)
{
for (int i = 0; i < x.second.size(); i++)
{
if(i== x.second.size()-1) cout << x.second[i];
else cout << x.second[i] << " ";
}
puts("");
break;
}
for (auto x : ansboy)
{
for (int i = 0; i < x.second.size(); i++)
{
if (i == x.second.size() - 1) cout << x.second[i];
else cout << x.second[i] << " ";
}
puts("");
break;
}
}
int main()
{
solve();
}
千手观音
根据输出的大小关系,建边,通过bfs跑出拓扑序,至于不确定的先后关系则通过优先队列排序再存进答案
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long ll;
map<string,int>mp;
int tot;
string st[10005];
vector<int>to[10005];
int in[10005];
void slove(){
int n;
cin>>n;
vector<string>pre;
for(int i=1;i<=n;i++){
string s;
cin>>s;
vector<string>now;
int cnt=0;
string t="";
for(int j=0;j<s.length();j++){
if(s[j]=='.'||j+1==s.length()){
if(j+1==s.length())t+=s[j];
if(!mp.count(t))mp[t]=++tot,st[tot]=t;
now.push_back(t);
t="";
}
else t+=s[j];
}
if(i==1)pre=now;
else{
if(pre.size()==now.size()){
for(int i=0;i<pre.size();i++){
if(pre[i]==now[i])continue;
to[mp[pre[i]]].push_back(mp[now[i]]);
in[mp[now[i]]]++;
break;
}
}
pre=now;
}
}
priority_queue<string,vector<string>,greater<string> >q;
for(int i=1;i<=tot;i++){
if(in[i]==0)q.push(st[i]);
}
vector<string>ans;
while(q.size()){
string t=q.top();q.pop();
int x=mp[t];
ans.push_back(t);
for(auto y:to[x]){
in[y]--;
if(in[y]==0){
q.push(st[y]);
}
}
}
bool p=false;
for(auto x:ans){
if(p)cout<<".";
p=true;
cout<<x;
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int T=1;
// cin>>T;
while(T--){
slove();
}
return 0;
}
关于深度优先搜索和逆序对的题应该不会很难吧这件事
把问题中的点拆分成两种,分别讨论,第一类点是有祖先关系的点对,第二类点是无关系的点对,对于第一类点,他的逆序对对数就是固定的,因为祖先关系是固定的,所以在任意个dfs序中,逆序对个数都是相同的,因此只需要找出祖先关系中有几对逆序对点即可,这一步可以通过树状数组维护,dfs遍历这个点时插入树状数组,作为祖先点,直到递归离开这个点,删去插入的这个点,每次遍历到一个新的点,就求出比这个点大的所有点的个数就是这个点所包含的逆序对个数,最后加起来就时这一部分答案。
第二类点这样的结点对在每种DFS序中的顺序不固定,但是我们经过观察完全可以发现,这样的结点对要不然是逆序对,要不然不是逆序对,概率都是1/2。
所以这一部分答案就是第二类点逆序对个数/2,但是第二类点逆序对个数怎么求呢,我们可以根据点对总数减去第一类点逆序对个数,也就是(n-1)*n/2-第一类点点对个数,第一类点点对个数我们可以根据
对每一个点找以这个点为根节点的子树的逆序对个数,可以发现只找左侧是根节点的点对个数就是子树除去根节点的节点个数,因此dfs过程中维护一下即可
最后需要求的是dfs序,这一部分需要dfs递归,从下往上更新得出,对于i节点,我们可以通过i节点的子节点的排列组合,以及各个子节点的dfs序相乘得到。从下往上更新最后就可以得到根节点开始的dfs序。
详见代码
#include<iostream>
#include<algorithm>
#include<cstring>
#define int long long
using namespace std;
const int N = 3e5 + 10, mod = 1e9 + 7;
int e[N*2], ne[N*2], idx, h[N];
int dp[N], cnt[N], root, a[N], n, deg[N], mx[N], jie[N];
int lowbit(int x)
{
return x & -x;
}
void init()
{
memset(h, -1, sizeof h);
jie[0] = 1;
for (int i = 1; i <= n; i++)
jie[i] = jie[i - 1] * i % mod;
}
int qmi(int a, int b, int m)
{
int res = 1;
a %= m;
while(b)
{
if (b & 1) res = res * a % m;
b >>= 1;
a = a * a % m;
}
return res;
}
void adde(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void add(int x, int val)
{
for (int i = x; i <= n; i+=lowbit(i))
a[i] += val;
}
int ask(int x)
{
int res = 0;
for (int i = x; i; i -= lowbit(i))
res += a[i],res%=mod;
return res;
}
void dfs(int r, int fa)
{
mx[r] = ask(n) - ask(r);
//cout << r << " r " << mx[r] << endl;
dp[r] = 1;
add(r, 1);
for (int i = h[r]; ~i; i = ne[i])
{
int j = e[i];
if (j == fa) continue;
deg[r]++;
dfs(j, r);
dp[r] = dp[r] * dp[j] % mod;
cnt[r] = (cnt[r] + cnt[j]) % mod;
}
dp[r] = (dp[r] * jie[deg[r]]) % mod;
cnt[r] = (cnt[r] + deg[r]) % mod;
add(r, -1);
}
int cal(int x)
{
return x * (x - 1) % mod * qmi(2, mod - 2, mod) % mod;
}
void solve()
{
cin >> n >> root;
init();
for (int i = 1; i < n; i++)
{
int a, b;
cin >> a >> b;
adde(a, b), adde(b, a);
}
dfs(root, 0);
int sum = cal(n);
for (int i = 1; i <= n; i++)
sum -= cnt[i],sum%=mod;
int res = sum * qmi(2, mod - 2, mod) % mod;
for (int i = 1; i <= n; i++)
res = (res + mx[i]) % mod;
res = res * dp[root] % mod;
cout << res << endl;
}
signed main()
{
solve();
}