“科林明伦杯”哈尔滨理工大学第十届程序设计竞赛(同步赛)题解

题目链接

按难度顺序

C.面积

题意:


如 图 所 示 , 正 方 形 周 围 接 4 个 半 圆 , 给 正 方 形 边 长 , 求 图 形 的 面 积 如图所示,正方形周围接4个半圆,给正方形边长,求图形的面积 4
题解:
正 方 形 边 长 的 一 半 就 是 圆 的 半 径 正方形边长的一半就是圆的半径
4 个 半 圆 就 是 两 个 圆 , 面 积 是 2 ∗ p i ∗ r 2 4个半圆就是两个圆,面积是2*pi*r^2 42pir2
正 方 形 d ∗ d 加 一 起 正方形d*d加一起 dd
AC代码

/*
    Author:zzugzx
    Lang:C++
    Blog:blog.csdn.net/qq_43756519
*/
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
//const int mod=1e9+7;
const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};


int main()
{
    //ios::sync_with_stdio(false);
    //cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int _;
    cin>>_;
    while(_--){
        double x;cin>>x;
        double ans=(2*(x/2)*(x/2)*3.14)+x*x;
        printf("%.2f\n",ans);
    }
    
    return 0;
}


E.赛马

题意:
小 明 和 同 学 各 有 n 匹 马 , 每 个 马 有 战 力 值 小明和同学各有n匹马,每个马有战力值 n
两 匹 马 比 赛 战 力 高 的 获 胜 两匹马比赛战力高的获胜
已 知 同 学 的 出 战 顺 序 , 小 明 最 多 能 获 胜 几 局 , 每 匹 马 只 能 用 一 次 已知同学的出战顺序,小明最多能获胜几局,每匹马只能用一次
题解:
贪 心 贪心
对 自 己 和 同 学 的 马 的 战 力 都 进 行 排 序 对自己和同学的马的战力都进行排序
每 次 让 自 己 的 马 里 战 力 尽 可 能 低 的 去 挑 战 同 学 最 低 的 并 能 获 胜 每次让自己的马里战力尽可能低的去挑战同学最低的并能获胜
这 样 找 下 来 就 能 找 到 最 大 次 数 这样找下来就能找到最大次数
AC代码

/*
    Author:zzugzx
    Lang:C++
    Blog:blog.csdn.net/qq_43756519
*/
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
//const int mod=1e9+7;
const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};

int a[maxn],b[maxn];

int main()
{
    //ios::sync_with_stdio(false);
    //cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int _;
    cin>>_;
    while(_--){
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)cin>>a[i];
        for(int i=1;i<=n;i++)cin>>b[i];
        sort(a+1,a+1+n);sort(b+1,b+1+n);
        int ans=0,x=1;
        for(int i=1;i<=n;i++){
			while(a[x]<=b[i]&&x<=n)x++;
			if(x==n+1) break;
			x++;ans++;	
		}
        cout<<ans<<endl;
    }

    return 0;
}


H.直线

题意:
平 面 内 有 n 条 直 线 , 问 最 多 有 多 少 个 交 点 平面内有n条直线,问最多有多少个交点 n线
题解:
n 条 直 线 两 两 相 交 , 一 共 n ∗ ( n − 1 ) / 2 个 交 点 n条直线两两相交,一共n*(n-1)/2个交点 n线n(n1)/2
n < = 1 e 15 , 会 爆 l o n g l o n g , 所 以 考 虑 高 精 度 或 i n t 128 n<=1e15,会爆longlong,所以考虑高精度或_int128 n<=1e15,longlongint128
我 这 里 用 的 是 p y t h o n 我这里用的是python python
AC代码

t=int(input())
for i in range(t):
    n=int(input())
    print(n*(n-1)//2)

B. 减成一

题意:
n 个 数 , 每 次 可 以 对 区 间 进 行 减 一 n个数,每次可以对区间进行减一 n
最 少 多 少 次 能 让 每 个 数 都 变 成 1 最少多少次能让每个数都变成1 1
题解:
差 分 差分
假 设 第 0 个 数 是 1 假设第0个数是1 01
然 后 求 出 差 分 数 组 , 想 让 每 个 数 都 变 成 1 然后求出差分数组,想让每个数都变成1 1
其 实 就 是 求 这 些 差 分 数 组 正 数 的 和 其实就是求这些差分数组正数的和
因 为 只 有 后 一 个 数 比 前 一 个 大 的 时 候 , 需 要 把 后 一 个 数 再 多 减 去 因为只有后一个数比前一个大的时候,需要把后一个数再多减去
AC代码

/*
    Author:zzugzx
    Lang:C++
    Blog:blog.csdn.net/qq_43756519
*/
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int mod=1e9+7;
//const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};

int a[maxn];

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int _;
    cin>>_;
    while(_--){
        int n;cin>>n;
        for(int i=1;i<=n;i++)cin>>a[i];
        a[0]=1;
        int ans=0;
        for(int i=1;i<=n;i++)
            if(a[i]-a[i-1]>0)ans+=a[i]-a[i-1];
        cout<<ans<<endl;
    }
    return 0;
}


J.最大值

题意:
给 一 个 字 符 串 , 问 字 符 串 中 给一个字符串,问字符串中
有 哪 个 非 前 缀 字 符 串 等 于 字 符 串 的 前 缀 有哪个非前缀字符串等于字符串的前缀
问 这 个 非 前 缀 字 符 串 最 长 是 多 少 问这个非前缀字符串最长是多少
题解:
这 道 题 我 看 方 法 有 很 多 这道题我看方法有很多
我 写 的 方 法 是 魔 改 了 一 下 K M P 算 法 我写的方法是魔改了一下KMP算法 KMP
将 原 字 符 串 设 为 模 式 串 将原字符串设为模式串
把 原 字 符 串 的 第 一 个 字 符 去 掉 后 去 作 为 整 串 把原字符串的第一个字符去掉后去作为整串
然 后 进 行 K M P 匹 配 , 进 行 K M P 匹 配 的 过 程 中 然后进行KMP匹配,进行KMP匹配的过程中 KMPKMP
维 护 一 下 模 式 串 的 指 针 最 远 能 指 到 哪 个 位 置 , 这 个 位 置 就 是 最 长 匹 配 维护一下模式串的指针最远能指到哪个位置,这个位置就是最长匹配
AC代码

/*
    Author:zzugzx
    Lang:C++
    Blog:blog.csdn.net/qq_43756519
*/
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
//const int mod=1e9+7;
const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};

string pa,str;
int nx[maxn],ans;
inline void GetNext()
{
    int i = 0, j = -1, len = pa.length();
    nx[i] = j;
    while(i < len){
        while( j != -1 && pa[i] != pa[j]) j = nx[j];
        nx[++i] = ++j;
    }
}
int Kmp()
{
    GetNext();
    int i =0, j = 0, lens=str.length(),lenp=pa.length();
    while(i < lens && j < lenp){
        while( j != -1 && str[i] != pa[j]) j = nx[j];
        i++, j++;
        ans=max(ans,j);
    }
    if(j == lenp) return i - lenp;///返回模式串在主串中首次出现的下标 +1是位置
    else return -1;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int _;
    cin>>_;
    while(_--){
        cin>>pa;ans=0;
        str=pa;str[0]='.';
        Kmp();cout<<ans<<endl;
    }

    return 0;
}

D.扔硬币

题意:
扔 n 个 硬 币 , 正 反 概 率 各 为 一 半 扔n个硬币,正反概率各为一半 n
如 果 已 知 最 少 有 m 个 硬 币 是 反 面 , 恰 好 有 k 个 硬 币 是 正 面 的 概 率 是 多 少 如果已知最少有m个硬币是反面,恰好有k个硬币是正面的概率是多少 mk
题解:
首 先 特 判 一 下 , 如 果 n − m 即 剩 余 的 硬 币 根 本 不 够 k 个 首先特判一下,如果n-m即剩余的硬币根本不够k个 nmk
那 么 说 明 根 本 不 可 能 有 k 个 硬 币 是 正 面 那么说明根本不可能有k个硬币是正面 k
概 率 一 定 为 0 概率一定为0 0

然 后 可 以 看 出 来 , 这 是 一 个 条 件 概 率 然后可以看出来,这是一个条件概率
条 件 概 率 的 公 式 为 条件概率的公式为
P ( A ∣ B ) = P ( A B ) / P ( B ) P(A|B)=P(AB)/P(B) P(AB)=P(AB)/P(B)
很 明 显 , 这 里 的 P ( B ) 为 至 少 m 个 硬 币 是 反 面 很明显,这里的P(B)为至少m个硬币是反面 P(B)m
那 么 求 恰 好 有 0 个 , 1 个 , … , m − 1 个 硬 币 是 反 面 那么求恰好有0个,1个,…,m-1个硬币是反面 01m1
用 1 减 去 即 是 P ( B ) , 对 于 每 种 情 况 就 是 C n i / ( 2 n ) 用1减去即是P(B),对于每种情况就是C_n^i/(2^n) 1P(B)Cni/(2n)
由 于 是 模 数 所 以 除 法 都 需 要 用 逆 元 由于是模数所以除法都需要用逆元
P ( A B ) 其 实 由 于 特 判 和 P ( B ) 没 有 什 么 关 系 P(AB)其实由于特判和P(B)没有什么关系 P(AB)P(B)
结 果 就 是 恰 好 k 个 硬 币 是 正 面 结果就是恰好k个硬币是正面 k
直 接 组 合 即 可 , C n k / ( 2 n ) 直接组合即可,C_n^k/(2^n) Cnk/(2n)
然 后 用 P ( A B ) ∗ i n v ( P ( B ) ) 然后用P(AB)*inv(P(B)) P(AB)inv(P(B))
AC代码

/*
    Author:zzugzx
    Lang:C++
    Blog:blog.csdn.net/qq_43756519
*/
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int mod=1e9+7;
//const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};


ll fact[maxn],inv1[maxn],a[maxn];
ll Pow(ll a, ll b){
	ll ans = 1;
	while(b > 0){
		if(b & 1){
			ans = ans * a % mod;
		}
		a = a * a % mod;
		b >>= 1;
	}
	return ans;
}
//逆元
ll inv(ll b){
    return Pow(b,mod-2)%mod;
}



ll C(ll n,ll m){
    if(m>n||n<0||m<0)return 0;
    if(m==0||m==n) return 1;
    ll res=(fact[n]*inv1[m]%mod*inv1[n-m])%mod;
    return res;
}

void init() {
	fact[0] = 1;
	for (int i = 1; i < maxn; i++) {
		fact[i] = fact[i - 1] * i %mod;
	}
	inv1[maxn - 1] = Pow(fact[maxn - 1], mod - 2);
	for (int i = maxn - 2; i >= 0; i--) {
		inv1[i] = inv1[i + 1] * (i + 1) %mod;
	}
}




int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int _;
    cin>>_;
    a[0]=1;
    init();
    for(int i=1;i<=100000;i++)a[i]=a[i-1]*inv(2)%mod;
    while(_--){
        ll n,m,k;cin>>n>>m>>k;
        if(n-m<k)cout<<0<<endl;
        else{
            ll y=0;
            for(int i=0;i<m;i++)
                y=(y+C(n,i)*a[n])%mod;
            y=(mod+1-y)%mod;
            ll x=C(n,k)*a[n]%mod;
            cout<<x*inv(y)%mod<<endl;
        }
    }

    return 0;
}


A.点对最大值

题意:
一 棵 树 上 的 点 和 边 都 有 对 应 的 权 值 一棵树上的点和边都有对应的权值
对 于 树 上 点 对 的 权 值 为 , 路 径 的 边 权 加 上 始 末 的 点 权 对于树上点对的权值为,路径的边权加上始末的点权
求 点 对 的 最 大 值 求点对的最大值
题解:
树 形 D P 树形DP DP
对 于 每 个 d p 数 组 维 护 以 i 为 端 点 的 最 大 点 对 值 对于每个dp数组维护以i为端点的最大点对值 dpi
可 以 将 每 个 点 看 作 与 自 己 相 连 , 边 权 为 0 可以将每个点看作与自己相连,边权为0 0
然 后 始 末 点 都 是 自 己 , 那 么 点 对 值 就 是 点 权 的 二 倍 然后始末点都是自己,那么点对值就是点权的二倍
对 于 每 一 条 边 , 更 新 如 果 这 条 边 连 接 他 两 端 对 应 的 链 对于每一条边,更新如果这条边连接他两端对应的链
是 否 能 得 到 一 个 更 大 的 结 果 , 每 次 更 新 这 个 最 大 结 果 是否能得到一个更大的结果,每次更新这个最大结果
d p 数 组 更 新 从 任 一 子 节 点 到 它 的 最 大 点 对 值 dp数组更新从任一子节点到它的最大点对值 dp
每 次 从 d p [ v ] 转 移 到 d p [ u ] 的 时 候 每次从dp[v]转移到dp[u]的时候 dp[v]dp[u]
d p [ v ] − v a l [ v ] + w + v a l [ u ] 使 得 v 为 端 点 的 链 端 点 变 u dp[v]-val[v]+w+val[u]使得v为端点的链端点变u dp[v]val[v]+w+val[u]使vu
然 后 最 后 输 出 维 护 的 最 大 结 果 然后最后输出维护的最大结果
AC代码

/*
    Author:zzugzx
    Lang:C++
    Blog:blog.csdn.net/qq_43756519
*/
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int mod=1e9+7;
//const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};

vector<pii> g[maxn];
ll val[maxn],dp[maxn],ans;
void dfs(int u,int fa){
    dp[u]=2*val[u];
    for(auto i:g[u]){
        int v=i.fi,w=i.se;
        if(v==fa)continue;
        dfs(v,u);
        ans=max(ans,dp[u]-val[u]+dp[v]-val[v]+w);
        dp[u]=max(dp[u],val[u]+dp[v]-val[v]+w);
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int _;
    cin>>_;
    while(_--){
        int n;cin>>n;
        for(int i=1;i<=n;i++)g[i].clear();
        for(int i=2;i<=n;i++){
            int v,w;
            cin>>v>>w;
            g[i].pb(mp(v,w));
            g[v].pb(mp(i,w));
        }
        for(int i=1;i<=n;i++)cin>>val[i];
        ans=-8e18;
        dfs(1,0);
        cout<<ans<<endl;
    }
    return 0;
}


G.养花

题意:
小 明 有 n 棵 植 物 , 每 个 高 度 为 h i , 他 想 让 他 们 变 为 k 小明有n棵植物,每个高度为h_i,他想让他们变为k nhik
他 可 以 做 以 下 四 种 操 作 , 每 组 给 定 对 应 次 数 他可以做以下四种操作,每组给定对应次数
1. 将 高 度 为 a 0 的 变 为 b 0 1.将高度为a_0的变为b_0 1.a0b0
2. [ a 1 , a 2 ] 区 间 的 某 个 高 度 变 为 b 1 2.[a_1,a_2]区间的某个高度变为b_1 2.[a1,a2]b1
3. a 1 的 变 为 [ b 1 , b 2 ] 区 间 的 某 个 高 度 3.a_1的变为[b_1,b_2]区间的某个高度 3.a1[b1,b2]
4. [ a 1 , a 2 ] 区 间 的 某 个 高 度 变 为 [ b 1 , b 2 ] 的 某 个 高 度 4.[a_1,a_2]区间的某个高度变为[b_1,b_2]的某个高度 4.[a1,a2][b1,b2]
问 最 多 能 让 多 少 植 物 变 成 k 高 度 问最多能让多少植物变成k高度 k
题解:
网 络 流 网络流
这 道 题 存 在 高 度 的 转 换 和 最 终 个 数 的 统 计 这道题存在高度的转换和最终个数的统计
那 么 可 以 用 一 个 超 级 源 点 , 并 让 k 为 汇 点 那么可以用一个超级源点,并让k为汇点 k
超 级 源 点 指 向 每 个 高 度 流 量 为 1 , 到 达 k 即 为 一 条 增 广 路 , 说 明 可 以 变 为 k 超级源点指向每个高度流量为1,到达k即为一条增广路,说明可以变为k 1k广k
操 作 1 , 转 换 到 网 络 流 就 是 让 a 0 指 向 b 0 , 流 量 为 次 数 c i 操作1,转换到网络流就是让a_0指向b_0,流量为次数c_i 1a0b0ci
操 作 2 , 即 将 b 1 裂 点 , 流 量 为 c i 表 示 次 数 , a 1 到 a 2 流 向 它 操作2,即将b_1裂点,流量为c_i表示次数,a_1到a_2流向它 2b1ci,a1a2
操 作 3 , 类 似 操 作 2 , a 1 裂 点 , 流 量 为 次 数 , 流 向 b 1 到 c 1 操作3,类似操作2,a_1裂点,流量为次数,流向b_1到c_1 32a1b1c1
操 作 4 , 中 间 新 增 一 个 过 渡 点 , 并 将 这 个 过 渡 点 裂 点 , 流 量 为 次 数 操作4,中间新增一个过渡点,并将这个过渡点裂点,流量为次数 4
a 1 到 a 2 流 向 这 个 点 , 这 个 点 流 向 b 1 到 b 2 a_1到a_2流向这个点,这个点流向b_1到b_2 a1a2b1b2
按 照 这 样 建 好 图 直 接 跑 最 大 流 即 可 按照这样建好图直接跑最大流即可
AC代码

/*
    Author:zzugzx
    Lang:C++
    Blog:blog.csdn.net/qq_43756519
*/
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int mod=1e9+7;
//const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};

//dinic
int n,m,s,t,N;
struct edge{
	int v,nx;
	int f;
}e[200010];
int head[maxn],cnt,cur[maxn],dep[maxn];
void init(){
	cnt=0;
	for(int i=0;i<=N;i++)
		head[i]=-1;
}
void add(int u,int v,int w){
	e[cnt]={v,head[u],w};
	head[u]=cnt++;
	e[cnt]={u,head[v],0};
	head[v]=cnt++;
}
bool bfs(){
	for(int i=0;i<=N;i++)cur[i]=head[i],dep[i]=0;
	queue<int> q;
	q.push(s);dep[s]=1;
	while(!q.empty()){
		int u=q.front();
		q.pop();
		for(int i=head[u];i!=-1;i=e[i].nx){
			int v=e[i].v;
			if(e[i].f&&!dep[v]){
				dep[v]=dep[u]+1;
				if(v==t)return 1;
				q.push(v);
			}
		}
	}
	return 0;
}
int dfs(int u,int lim){
	if(u==t)return lim;
	int ans=0,v,tmp;
	for(int i=cur[u];i!=-1;i=e[i].nx){
		cur[u]=i;
		v=e[i].v;
		if(dep[v]==dep[u]+1&&e[i].f){
			tmp=dfs(v,min(lim,e[i].f));
			e[i].f-=tmp;
			e[i^1].f+=tmp;
			ans+=tmp;
			lim-=tmp;
			if(!lim)break;
		}
	}
	if(!ans||lim)dep[u]=0;
	return ans;
}
int dinic(){
	int ans=0;
	while(bfs())ans+=dfs(s,inf);
	return ans;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int _;
    cin>>_;
    while(_--){
        int n,m,k;
        cin>>n>>m>>k;
        s=0,N=k+2*m+1,t=k;
        init();
        for(int i=1,x;i<=n;i++){
            cin>>x;
            add(s,x,1);
        }
        for(int i=1;i<=m;i++){
            int op,c;
            cin>>op>>c;
            if(op==1){
                int a,b;
                cin>>a>>b;
                add(a,b,c);
            }
            if(op==2){
                int a1,a2,b;
                cin>>a1>>a2>>b;
                for(int j=a1;j<=a2;j++)
                    add(j,k+i,c);
                add(k+i,b,c);
            }
            if(op==3){
                int a,b1,b2;
                cin>>a>>b1>>b2;
                for(int j=b1;j<=b2;j++)
                    add(k+i,j,c);
                add(a,k+i,c);
            }
            if(op==4){
                int a1,a2,b1,b2;
                cin>>a1>>a2>>b1>>b2;
                for(int j=a1;j<=a2;j++)
                    add(j,k+i,c);
                add(k+i,k+i+m,c);
                for(int j=b1;j<=b2;j++)
                    add(k+i+m,j,c);
            }
        }
        cout<<dinic()<<endl;
    }
    return 0;
}


I.字典序

题意:
给 定 一 个 长 度 为 n 的 数 组 a 给定一个长度为n的数组a na
将 去 掉 第 i 个 元 素 后 的 数 组 写 为 s i 将去掉第i个元素后的数组写为s_i isi
将 s i 按 字 典 序 排 序 , 并 依 次 输 出 i 将s_i按字典序排序,并依次输出i sii
( 字 典 序 相 同 i 从 小 到 大 输 出 ) (字典序相同i从小到大输出) (i)
题解:
对 于 一 个 数 , 如 果 大 于 下 一 个 数 , 去 掉 后 , 字 典 序 变 小 对于一个数,如果大于下一个数,去掉后,字典序变小
如 果 等 于 , 不 论 去 掉 哪 个 都 是 字 典 序 都 是 相 同 的 如果等于,不论去掉哪个都是字典序都是相同的
如 果 小 于 下 一 个 数 , 去 掉 后 字 典 序 变 大 如果小于下一个数,去掉后字典序变大

所 以 需 要 做 的 就 是 , 先 对 数 进 行 去 重 , 并 记 录 相 同 数 的 左 右 位 置 所以需要做的就是,先对数进行去重,并记录相同数的左右位置
由 于 从 左 往 右 , 第 一 个 大 于 的 数 字 典 序 是 最 大 的 由于从左往右,第一个大于的数字典序是最大的
第 一 个 小 于 的 字 典 序 是 最 小 的 第一个小于的字典序是最小的
所 以 我 们 倒 着 走 , 这 就 很 类 似 堆 栈 了 所以我们倒着走,这就很类似堆栈了
如 果 遇 到 小 于 下 一 个 数 的 往 右 放 , 否 则 往 左 放 ( 左 到 右 字 典 序 增 大 ) 如果遇到小于下一个数的往右放,否则往左放(左到右字典序增大) ()
这 个 放 的 是 位 置 , 如 果 这 个 数 没 有 相 同 数 , 刚 记 录 的 左 右 位 置 相 等 这个放的是位置,如果这个数没有相同数,刚记录的左右位置相等
这 个 位 置 也 是 他 原 本 的 位 置 这个位置也是他原本的位置
如 果 这 个 数 有 相 同 的 数 , 从 刚 记 录 的 左 位 置 输 出 到 右 位 置 如果这个数有相同的数,从刚记录的左位置输出到右位置
这 样 最 终 放 完 的 这 个 顺 序 就 是 答 案 这样最终放完的这个顺序就是答案
可 以 想 一 下 , 往 左 放 往 右 放 的 数 据 结 构 可以想一下,往左放往右放的数据结构
最 好 用 的 明 显 就 是 s t l 的 d e q u e , 可 以 实 现 这 一 操 作 最好用的明显就是stl的deque,可以实现这一操作 stldeque
AC代码

/*
    Author:zzugzx
    Lang:C++
    Blog:blog.csdn.net/qq_43756519
*/
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int mod=1e9+7;
//const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};

int l[maxn],r[maxn],a[maxn];

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int _;
    cin>>_;
    while(_--){
        int n;cin>>n;
        for(int i=1;i<=n;i++)cin>>a[i];
        int cnt=0;
        for(int i=1;i<=n;i++){
            int j=i;
            while(a[j+1]==a[j]&&j+1<=n)j++;
            a[++cnt]=a[i],l[cnt]=i,r[cnt]=j;
            i=j;
        }
        a[cnt+1]=0;deque<int> q;
        for(int i=cnt;i;i--)
            if(a[i]>a[i+1])q.push_front(i);
            else q.pb(i);
        for(auto i:q)
            for(int j=l[i];j<=r[i];j++)
                cout<<j<<' ';
        cout<<endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值