出题数:5
排名:180
H.Holding Two
WYX
题意:
输出一个n*m的矩阵,矩阵中满足在横行,竖行,斜行中,任意的连续的3个的元素不能都为0,或都为1。
题解:
构造一个这样的矩阵
0 0 1 1 0 0 1 1 ……
1 1 0 0 1 1 0 0 ……
0 0 1 1 0 0 1 1 ……
1 1 0 0 1 1 0 0 ……
0 0 1 1 0 0 1 1 ……
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int n,m;cin>>n>>m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if((j/2)&1) cout<<(0^(i&1));
else cout<<(1^(i&1));
}
cout<<endl;
}
return 0;
}
B.Boxes
WXL+CY
#include <bits/stdc++.h>
typedef long long ll;
const int MAXN = 1e5 + 10;
double w[MAXN], C, pre[MAXN], suf[MAXN];
int n;
double sum = 0;
int main()
{
scanf("%d%lf", &n, &C);
for (int i = 1; i <= n; ++i)
{
scanf("%lf",&w[i]);
sum += w[i];
}
std::sort(w + 1, w + 1 + n);
double p = 0.5, ans = C;
for (int i = n-1; i >= 1; --i)
{
ans += p * w[i];
p *= 0.5;
p += 0.5;
}
if(sum <= ans)
{
printf("%.10lf\n",sum);
}
else
{
printf("%.10lf\n", ans);
}
return 0;
}
K.King of Range
WYX
题意
给你一个长为n的数组,有m次询问,每次询问给你一个k,问有多少对(l,r),使数组区间l到r的最大值与最小值的差大于k
WYX写的线段树,应该不用这么麻烦
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=4e5+10;
int a[maxn],c[maxn];
int tree[maxn][2];
void build(int l,int r,int x) //建树,x为编号,l,r为其表示的区间
{
if(l==r) {
tree[x][0]=a[l];
tree[x][1]=a[l];
return ;
}
int mid=(l+r)/2;
build(l,mid,x<<1);
build(mid+1,r,x<<1|1);
tree[x][0]=min(tree[x<<1][0],tree[x<<1|1][0]);
tree[x][1]=max(tree[x<<1][1],tree[x<<1|1][1]);
}
int query(int l,int r,int x,int st,int ed) //min
{ //查询操作 ,st与ed为查询区间
if(st<=l&&r<=ed) return tree[x][0];
int mid=(l+r)/2,ans=1e9+10;
if(st<=mid) ans=query(l,mid,x<<1,st,ed); //x<<1表示x*2
if(ed>mid) ans=min(ans,query(mid+1,r,x<<1|1,st,ed));
return ans;
}
int query1(int l,int r,int x,int st,int ed)
{ //查询操作 ,st与ed为查询区间
if(st<=l&&r<=ed) return tree[x][1];
int mid=(l+r)/2,ans=0;
if(st<=mid) ans=query1(l,mid,x<<1,st,ed); //x<<1表示x*2
if(ed>mid) ans=max(ans,query1(mid+1,r,x<<1|1,st,ed));
return ans;
}
int f[maxn][50],lg2[maxn]; //log2[x]表示对log2(x)向下取整
int f1[maxn][50];
void init(int k,int n) //k=log2(maxn)
{
for(int i=1;i<=n;i++)
f[i][0]=a[i],f1[i][0]=a[i]; //a为输入的数组
for(int j=1;j<k;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
{
f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
f1[i][j]=min(f1[i][j-1],f1[i+(1<<(j-1))][j-1]);
}
lg2[1]=0;
for(int i=2;i<=n;i++) //预处理log
lg2[i]=lg2[i/2]+1;
}
int st(int l,int r)
{
int s=lg2[r-l+1];
return max(f[l][s],f[r-(1<<s)+1][s]);
}
int st1(int l,int r)
{
int s=lg2[r-l+1];
return min(f1[l][s],f1[r-(1<<s)+1][s]);
}
int main()
{
// ios_base::sync_with_stdio(false);
// cin.tie(nullptr);
// cout.tie(nullptr);
int n,m;scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);//build(1,n,1);
init(30,n);
while(m--)
{
int k; scanf("%d",&k);
ll ans=0;
int l=1;
for(int i=1;i<=n;i++)
{
//while(l<=i&&query1(1,n,1,l,i)-query(1,n,1,l,i)>k) l++;
while(l<=i&&st(l,i)-st1(l,i)>k) l++;
ans+=i-l+1;
}
ans=1ll*n*(n+1)/2-ans;
printf("%lld\n",ans);
}
return 0;
}
/*
3 1
1 5 1
3
*/
这里还有一个双指针的做法:
若给你个子数组发现最大值与最小值的差已经满足条件,那么是不是意味着在这个子数组的基础上在添加其他的元素,其最大值与最小值的差也会成立。所以我们可以用双子针,固定i的位置,来找最小的j。要在一个区间内找最小值,我们可以用st表。
#include <bits/stdc++.h>
using namespace std;
#define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
typedef long long ll; typedef unsigned long long ull; typedef long double ld;
inline ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; }
ll qpow(ll a, ll b) { ll ans = 1; while (b) { if (b & 1) ans *= a; b >>= 1; a *= a; } return ans; }
ll qpow(ll a, ll b, ll mod) { ll ans = 1; while (b) { if (b & 1)(ans *= a) %= mod; b >>= 1; (a *= a) %= mod; }return ans % mod; }
const int mod=1e9+7;
const int N=1e5+7;
int n,m,l,r;
int Log[N]; // 用来求log的
int stmax[N][22];
int stmin[N][22];
void fun(){//求log的函数
Log[1]=0;
for(int i=2;i<=n;i++)
Log[i]=Log[i/2]+1;
}
bool search(int l,int r,ll k){//判断区间l到r是否可以
int s=Log[r-l+1]; //求log的值
int ma=max(stmax[l][s], stmax[r-(1<<s)+1][s]);//区间最大值
int mi=min(stmin[l][s], stmin[r-(1<<s)+1][s]);//区间最小值
if(ma-mi>k) return true; //判断是否大于k
else return false;
}
int main(){
while(cin>>n>>m){
fun();
for(int i=1;i<=n;i++) {cin>>stmax[i][0];stmin[i][0]=stmax[i][0];}
for(int j=1;j<=21;j++)//构造st表
for(int i=1;i+(1<<j)-1<=n;i++){
stmax[i][j]=max(stmax[i][j-1],stmax[i+(1<<(j-1))][j-1]);
stmin[i][j]=min(stmin[i][j-1],stmin[i+(1<<(j-1))][j-1]);
}
while(m--){
ll k,ans=0;
cin>>k;
for(int i=1,j=1;i<=n;i++){
while(!search(i,j,k)&&j<=n&&i<=j){//固定i的值,找到成立的j的最小值
j++;
}
if(j<=n) ans=ans+n-j+1; //如果某一子段可以,则无论后面加上什么数形成的数组都可以
}
cout<<ans<<endl;
}
}
return 0;
}
D.Double Strings
CY
dp
#include <bits/stdc++.h>
typedef long long ll;
const int MAXN = 5e3 + 10, MOD = 1e9 + 7;
int dp1[MAXN][MAXN], dp2[MAXN][MAXN];
char a[MAXN], b[MAXN];
int main()
{
scanf("%s%s", a + 1, b + 1);
int n = strlen(a + 1), m = strlen(b + 1);
for (int i = 0; i <= m; ++i)
dp1[0][i] = 1;
for (int i = 0; i <= n; ++i)
dp1[i][0] = 1;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
{
dp1[i][j] = ((dp1[i - 1][j] + dp1[i][j - 1] - dp1[i - 1][j - 1]) % MOD + MOD) % MOD;
if (a[i] == b[j]) dp1[i][j] = (dp1[i][j] + dp1[i - 1][j - 1]) % MOD;
}
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
{
dp2[i][j] = (dp2[i - 1][j] + dp2[i][j - 1]) % MOD;
if (a[i] < b[j]) dp2[i][j] = (dp2[i][j] + dp1[i - 1][j - 1]) % MOD;
}
printf("%d\n", dp2[n][m]);
return 0;
}
J.Jewels
WXL+WYX
题意:
打捞 nn 个货物,货物会动,每一个时刻只能打捞一个,货物会动,打捞的代价是三维空间上的距离平方。
n 个货物只需要
[
0
,
n
−
1
]
[0, n - 1]
[0,n−1]时刻就能全部打捞,对于每个货物在每一个时刻都有相应的代价,可以构建二分图,左边是时刻,右边是货物,做带权二分图的最优匹配(KM算法)即可。
ps:刚开始WYX用的EK算法TLE了,使用KM算法才过
复杂度
O
(
n
3
)
O(n^3)
O(n3)
/*
* @Author: Kurisu
*/
#include<bits/stdc++.h>
const int mod = 998244353;
const int N = 2e5 + 5;
long long x[305], y[305], z[305], v[305];
long long w[305][305]; // cost matrix
namespace KM {
long long cal(int n, int m) {
std::vector<long long> u(n + 1), v(m + 1), p(m + 1), way(m + 1);
for (int i = 1; i <= n; i++) {
p[0] = i;
long long j0 = 0;
std::vector<long long> minv(m + 1, 1e18);
std::vector<char> used(m + 1, false);
do {
used[j0] = true;
long long i0 = p[j0], delta = 1e18, j1;
for (int j = 1; j <= m; ++j) {
if (!used[j]) {
long long cur = w[i0][j] - u[i0] - v[j];
if (cur < minv[j]) {
minv[j] = cur, way[j] = j0;
}
if (minv[j] < delta) {
delta = minv[j], j1 = j;
}
}
}
for (int j = 0; j <= m; ++j) {
if (used[j]) {
u[p[j]] += delta, v[j] -= delta;
}
else {
minv[j] -= delta;
}
}
j0 = j1;
} while (p[j0] != 0);
do {
long long j1 = way[j0];
p[j0] = p[j1];
j0 = j1;
} while (j0);
}
long long res = 0;
for (int i = 1; i <= m; i++) {
res += w[p[i]][i];
}
return res;
}
}
long long get_cost(int id, int t) {
return x[id] * x[id] + y[id] * y[id] + 1LL * (z[id] + v[id] * t) * (z[id] + v[id] * t);
}
void solve() {
int n; std::cin >> n;
for (int i = 1; i <= n; i++) {
std::cin >> x[i] >> y[i] >> z[i] >> v[i];
}
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= n - 1; j++) {
w[i][j + 1] = get_cost(i, j);
}
}
std::cout << KM::cal(n, n) << '\n';
}
signed main() {
std::cin.sync_with_stdio(false), std::cin.tie(nullptr);
int T = 1; //std::cin >> T;
while (T--) {
solve();
}
return 0;
}