按难度顺序
C.面积
题意:
如
图
所
示
,
正
方
形
周
围
接
4
个
半
圆
,
给
正
方
形
边
长
,
求
图
形
的
面
积
如图所示,正方形周围接4个半圆,给正方形边长,求图形的面积
如图所示,正方形周围接4个半圆,给正方形边长,求图形的面积
题解:
正
方
形
边
长
的
一
半
就
是
圆
的
半
径
正方形边长的一半就是圆的半径
正方形边长的一半就是圆的半径
4
个
半
圆
就
是
两
个
圆
,
面
积
是
2
∗
p
i
∗
r
2
4个半圆就是两个圆,面积是2*pi*r^2
4个半圆就是两个圆,面积是2∗pi∗r2
正
方
形
d
∗
d
加
一
起
正方形d*d加一起
正方形d∗d加一起
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∗(n−1)/2个交点
n
<
=
1
e
15
,
会
爆
l
o
n
g
l
o
n
g
,
所
以
考
虑
高
精
度
或
i
n
t
128
n<=1e15,会爆longlong,所以考虑高精度或_int128
n<=1e15,会爆longlong,所以考虑高精度或int128
我
这
里
用
的
是
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
假设第0个数是1
然
后
求
出
差
分
数
组
,
想
让
每
个
数
都
变
成
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匹配的过程中
然后进行KMP匹配,进行KMP匹配的过程中
维
护
一
下
模
式
串
的
指
针
最
远
能
指
到
哪
个
位
置
,
这
个
位
置
就
是
最
长
匹
配
维护一下模式串的指针最远能指到哪个位置,这个位置就是最长匹配
维护一下模式串的指针最远能指到哪个位置,这个位置就是最长匹配
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个硬币是正面的概率是多少
如果已知最少有m个硬币是反面,恰好有k个硬币是正面的概率是多少
题解:
首
先
特
判
一
下
,
如
果
n
−
m
即
剩
余
的
硬
币
根
本
不
够
k
个
首先特判一下,如果n-m即剩余的硬币根本不够k个
首先特判一下,如果n−m即剩余的硬币根本不够k个
那
么
说
明
根
本
不
可
能
有
k
个
硬
币
是
正
面
那么说明根本不可能有k个硬币是正面
那么说明根本不可能有k个硬币是正面
概
率
一
定
为
0
概率一定为0
概率一定为0
然
后
可
以
看
出
来
,
这
是
一
个
条
件
概
率
然后可以看出来,这是一个条件概率
然后可以看出来,这是一个条件概率
条
件
概
率
的
公
式
为
条件概率的公式为
条件概率的公式为
P
(
A
∣
B
)
=
P
(
A
B
)
/
P
(
B
)
P(A|B)=P(AB)/P(B)
P(A∣B)=P(AB)/P(B)
很
明
显
,
这
里
的
P
(
B
)
为
至
少
m
个
硬
币
是
反
面
很明显,这里的P(B)为至少m个硬币是反面
很明显,这里的P(B)为至少m个硬币是反面
那
么
求
恰
好
有
0
个
,
1
个
,
…
,
m
−
1
个
硬
币
是
反
面
那么求恰好有0个,1个,…,m-1个硬币是反面
那么求恰好有0个,1个,…,m−1个硬币是反面
用
1
减
去
即
是
P
(
B
)
,
对
于
每
种
情
况
就
是
C
n
i
/
(
2
n
)
用1减去即是P(B),对于每种情况就是C_n^i/(2^n)
用1减去即是P(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为端点的最大点对值
对于每个dp数组维护以i为端点的最大点对值
可
以
将
每
个
点
看
作
与
自
己
相
连
,
边
权
为
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]使得v为端点的链端点变u
然
后
最
后
输
出
维
护
的
最
大
结
果
然后最后输出维护的最大结果
然后最后输出维护的最大结果
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
小明有n棵植物,每个高度为hi,他想让他们变为k
他
可
以
做
以
下
四
种
操
作
,
每
组
给
定
对
应
次
数
他可以做以下四种操作,每组给定对应次数
他可以做以下四种操作,每组给定对应次数
1.
将
高
度
为
a
0
的
变
为
b
0
1.将高度为a_0的变为b_0
1.将高度为a0的变为b0
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
超级源点指向每个高度流量为1,到达k即为一条增广路,说明可以变为k
操
作
1
,
转
换
到
网
络
流
就
是
让
a
0
指
向
b
0
,
流
量
为
次
数
c
i
操作1,转换到网络流就是让a_0指向b_0,流量为次数c_i
操作1,转换到网络流就是让a0指向b0,流量为次数ci
操
作
2
,
即
将
b
1
裂
点
,
流
量
为
c
i
表
示
次
数
,
a
1
到
a
2
流
向
它
操作2,即将b_1裂点,流量为c_i表示次数,a_1到a_2流向它
操作2,即将b1裂点,流量为ci表示次数,a1到a2流向它
操
作
3
,
类
似
操
作
2
,
a
1
裂
点
,
流
量
为
次
数
,
流
向
b
1
到
c
1
操作3,类似操作2,a_1裂点,流量为次数,流向b_1到c_1
操作3,类似操作2,a1裂点,流量为次数,流向b1到c1
操
作
4
,
中
间
新
增
一
个
过
渡
点
,
并
将
这
个
过
渡
点
裂
点
,
流
量
为
次
数
操作4,中间新增一个过渡点,并将这个过渡点裂点,流量为次数
操作4,中间新增一个过渡点,并将这个过渡点裂点,流量为次数
a
1
到
a
2
流
向
这
个
点
,
这
个
点
流
向
b
1
到
b
2
a_1到a_2流向这个点,这个点流向b_1到b_2
a1到a2流向这个点,这个点流向b1到b2
按
照
这
样
建
好
图
直
接
跑
最
大
流
即
可
按照这样建好图直接跑最大流即可
按照这样建好图直接跑最大流即可
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
给定一个长度为n的数组a
将
去
掉
第
i
个
元
素
后
的
数
组
写
为
s
i
将去掉第i个元素后的数组写为s_i
将去掉第i个元素后的数组写为si
将
s
i
按
字
典
序
排
序
,
并
依
次
输
出
i
将s_i按字典序排序,并依次输出i
将si按字典序排序,并依次输出i
(
字
典
序
相
同
i
从
小
到
大
输
出
)
(字典序相同i从小到大输出)
(字典序相同i从小到大输出)
题解:
对
于
一
个
数
,
如
果
大
于
下
一
个
数
,
去
掉
后
,
字
典
序
变
小
对于一个数,如果大于下一个数,去掉后,字典序变小
对于一个数,如果大于下一个数,去掉后,字典序变小
如
果
等
于
,
不
论
去
掉
哪
个
都
是
字
典
序
都
是
相
同
的
如果等于,不论去掉哪个都是字典序都是相同的
如果等于,不论去掉哪个都是字典序都是相同的
如
果
小
于
下
一
个
数
,
去
掉
后
字
典
序
变
大
如果小于下一个数,去掉后字典序变大
如果小于下一个数,去掉后字典序变大
所
以
需
要
做
的
就
是
,
先
对
数
进
行
去
重
,
并
记
录
相
同
数
的
左
右
位
置
所以需要做的就是,先对数进行去重,并记录相同数的左右位置
所以需要做的就是,先对数进行去重,并记录相同数的左右位置
由
于
从
左
往
右
,
第
一
个
大
于
的
数
字
典
序
是
最
大
的
由于从左往右,第一个大于的数字典序是最大的
由于从左往右,第一个大于的数字典序是最大的
第
一
个
小
于
的
字
典
序
是
最
小
的
第一个小于的字典序是最小的
第一个小于的字典序是最小的
所
以
我
们
倒
着
走
,
这
就
很
类
似
堆
栈
了
所以我们倒着走,这就很类似堆栈了
所以我们倒着走,这就很类似堆栈了
如
果
遇
到
小
于
下
一
个
数
的
往
右
放
,
否
则
往
左
放
(
左
到
右
字
典
序
增
大
)
如果遇到小于下一个数的往右放,否则往左放(左到右字典序增大)
如果遇到小于下一个数的往右放,否则往左放(左到右字典序增大)
这
个
放
的
是
位
置
,
如
果
这
个
数
没
有
相
同
数
,
刚
记
录
的
左
右
位
置
相
等
这个放的是位置,如果这个数没有相同数,刚记录的左右位置相等
这个放的是位置,如果这个数没有相同数,刚记录的左右位置相等
这
个
位
置
也
是
他
原
本
的
位
置
这个位置也是他原本的位置
这个位置也是他原本的位置
如
果
这
个
数
有
相
同
的
数
,
从
刚
记
录
的
左
位
置
输
出
到
右
位
置
如果这个数有相同的数,从刚记录的左位置输出到右位置
如果这个数有相同的数,从刚记录的左位置输出到右位置
这
样
最
终
放
完
的
这
个
顺
序
就
是
答
案
这样最终放完的这个顺序就是答案
这样最终放完的这个顺序就是答案
可
以
想
一
下
,
往
左
放
往
右
放
的
数
据
结
构
可以想一下,往左放往右放的数据结构
可以想一下,往左放往右放的数据结构
最
好
用
的
明
显
就
是
s
t
l
的
d
e
q
u
e
,
可
以
实
现
这
一
操
作
最好用的明显就是stl的deque,可以实现这一操作
最好用的明显就是stl的deque,可以实现这一操作
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;
}