第一天的提高模拟测 考前特意睡了20min 还是歇菜了,果然自己菜是真实的。

题目质量海星 但是我都不会这是真的...题目由于是花钱买的这里就不放了 LINK:problem 熟悉我的人应该都知道账号和密码...

但是总该叙述一下题意 一个组两个人 一个组长一个组员 每个人都有两个属性w经验s工资要求w组长>=w组员 有一部分人是组长 一部分人是组员 一部分是既可以是组长也可以是组员。

现在问 要求组成k组的最小花费如果不可能的话输出-1.显然 2*k<=n...

而这里 有点像一个二分图 但是对于一部分既是组长又是组员的人很难判断究竟是组员还是组长通过以往的分析 此时就应该上网络流了 一个点两种选择然后 网络流一跑求个最优 但显然 建图...建不出来图的 费用流咕了.

考虑 暴力 这不就是爆搜的组合数么 搜一发 几个剪枝上去 发现最致命的原因是 无法判断方案的合法性想了一个贪心的做法 每个A都选择一个较大的B 然后不够选再选一个较小的C 最后C再选B 看能把A B 集合都清空不能 这样做(贪心 感觉是正确的 根据全局最优性原理好像也是可以证明的。不出意料的挂了 我不知道 哪写错了 (贪心 当时写的 做法C是从大到小的 但是我的答案小 所以问题不出在 C上 好像哪里写挂了 贪心正确性 也不好证明 这个40分的做法于是也咕了.

考虑 题解中的正解 dp 考虑一下 对w排序 从小到大按w排序 排完序之后 组长可以选择之前再其之前的组员 设状态 f[i][j][k]表示前i个人形成了j组有k个组员的最小代价。

//#include<bits/stdc++.h>
#include<iostream>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<cctype>
#include<utility>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<deque>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<iomanip>
#include<stack>
#include<string>
#include<cstring>
#define INF 1000000000000000ll
#define ll long long
#define db double
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)>(y)?(y):(x))
#define mp(x,y) make_pair(x,y)
using namespace std;
char *fs,*ft,buf[<<];
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline ll read()
{
ll x=,f=;char ch=getc();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getc();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getc();}
return f<?-x:x;
}
const ll MAXN=,maxn=;
ll n,k;
struct wy
{
ll w,s,op;
}t[MAXN];
inline ll cmp(wy a,wy b){return a.w==b.w?a.op<b.op:a.w<b.w;}
ll f[maxn][maxn];
int main()
{
freopen("1.in","r",stdin);
n=read();k=read();
if(*k>n){puts("-1");return ;}
for(ll i=;i<=n;++i)
{
ll w,s,op;
w=read();s=read();op=read();
t[i]=(wy){w,s,op};
if(t[i].op==)t[i].op=;
else
{
if(t[i].op==)t[i].op=;
else if(t[i].op==)t[i].op=;
}
}
sort(t+,t++n,cmp);
for(ll i=;i<=k;++i)
for(ll j=;j<=k;++j)
f[i][j]=INF;
f[][]=;
for(ll i=;i<=n;++i)
{
for(ll j=k;j>=;--j)
for(ll l=k;l>=;--l)
{
if(f[j][l]==INF)continue;
//成为组长
if(t[i].op!=)if(l->=&&j+<=k)f[j+][l-]=min(f[j+][l-],f[j][l]+t[i].s);
//成为组员
if(t[i].op!=)if(l+<=k)f[j][l+]=min(f[j][l+],f[j][l]+t[i].s);
}
}
if(f[k][]!=INF)printf("%lld\n",f[k][]);
else puts("-1");
return ;
}

很不错的思路 当时考试就顾着某个人和某个人的必要匹配了 没有想到还是和 具体匹配无关 只要的到合法的人数就好了。

T2 看题目看的就一脸蒙蔽 觉得非常不可写 于是就弃疗看T3了。

T2 一个n*m的平面上每个点都有颜色每次可以选取一条直线对折要求对折的下半部分>=上半部分 求 最后对折出来最下层有多少种本质不同的结果,本质不同的定义:最下层在原方格纸中对应的区域不同。

看起来这个问题很难解决 不妨来观察当n==1时的情况。先分析一下答案吧 不动是一种 然后对这一行采用manacher一下是必然的吧。。。(虽然我还没证明manacher本身的正确性 但还是可以用的.

经过手动模拟之后我们发现最后的答案其实为 l~r 题目中就是让我们找有多少个不同的l~r 很迷其实 l~r可以当做最后的区间的话那么l~n和1~r也是可以当做最后的区间的,因为左折和右折是独立的。

多少个本质不同的l r 显然 我们求出1~l之间的所有合法端点 * r[i]其是否能成为右端点 我们定右端点求左端点 和定左端点求右端点是是等效的。

怎么求 prei这个东西 显然的是 pre[i]=pre[i-1]+x;x=pre[i-1]-pre[t];t=i-ansi-1;ansi=以i~i+1为中心的回文半径。这个式子的第一部分显然 后一部分是当前点带来的贡献。落在i-ansi+1~i这个区间内的点都会使pre[i]得到贡献。

此时我们再求一个定点r即可。注意pre和buf数组的含义不尽相同。

//#include<bits/stdc++.h>
#include<iostream>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<cctype>
#include<utility>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<deque>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<iomanip>
#include<stack>
#include<string>
#include<cstring>
#define INF 2000000000
#define ll long long
#define db double
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)>(y)?(y):(x))
#define mp(x,y) make_pair(x,y)
using namespace std;
char *fs,*ft,buf[<<];
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline ll read()
{
ll x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return f<?-x:x;
}
const ll MAXN=;
ll n,m,cnt;
ll p[MAXN<<],w[MAXN];
char a[MAXN],b[MAXN<<];
ll pre[MAXN],r[MAXN],suf[MAXN];
inline void manacher(ll len,char *c)
{
ll mid=,mx=;
for(ll i=;i<=len;++i)
{
p[i]=i<mx?min(p[(mid<<)-i],mx-i):;
while(b[i-p[i]]==b[i+p[i]])++p[i];
if(mx<p[i]+i)mid=i,mx=p[i]+i;
}
for(ll i=;i<=m;++i)w[i]=p[i<<|]>>;
}
inline ll calc(ll n,char *c)
{
pre[]=;r[n]=;suf[n]=;
for(ll i=;i<=n;++i)
{
ll t=i-w[i]-;
ll x=pre[i-]-(t>=?pre[t]:);
pre[i]=pre[i-]+(x>);
}
for(ll i=n-;i>=;--i)
{
ll t=i+w[i]+;
ll x=suf[i+]-(t<=n?suf[t]:);
suf[i]=suf[i+]+(r[i]=(x>));
}
ll ans=;
for(ll i=;i<=n;++i)ans+=pre[i-]*r[i];
return ans;
}
signed main()
{
//freopen("1.in","r",stdin);
n=read();m=read();
if(n==)
{
scanf("%s",a+);
b[]='&';b[]='#';cnt=;
for(ll i=;i<=m;++i)b[++cnt]=a[i],b[++cnt]='#';
manacher(cnt,b);
printf("%lld\n",calc(m,a));
}
}

考虑 二维的折叠。发现横着叠竖着叠是不冲突的分别计算两个东西的方案数发现可以先横着叠再竖着叠或者先竖着叠再横着叠 相乘即可。

//#include<bits/stdc++.h>
#include<iostream>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<cctype>
#include<utility>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<deque>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<iomanip>
#include<stack>
#include<string>
#include<cstring>
#define INF 2000000000
#define mod 1000000007
#define P 131
#define ll long long
#define db double
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)>(y)?(y):(x))
#define mp(x,y) make_pair(x,y)
using namespace std;
char *fs,*ft,buf[<<];
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline ll read()
{
ll x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return f<?-x:x;
}
const ll MAXN=;
ll n,m,cnt;
ll p[MAXN<<],w[MAXN];
char a[MAXN];
ll b[MAXN<<];
ll pre[MAXN],r[MAXN],suf[MAXN],R[MAXN],C[MAXN];
inline void manacher(ll n,ll *c)
{
b[]=-;b[]=-;
ll len=;
for(ll i=;i<=n;++i)b[++len]=c[i],b[++len]=-;
ll mid=,mx=;
for(ll i=;i<=len;++i)
{
p[i]=i<mx?min(p[(mid<<)-i],mx-i):;
while(b[i-p[i]]==b[i+p[i]])++p[i];
if(mx<p[i]+i)mid=i,mx=p[i]+i;
}
for(ll i=;i<=n;++i)w[i]=p[i<<|]>>;
}
inline ll calc(ll n,ll *c)
{
manacher(n,c);
pre[]=;r[n]=;suf[n]=;
for(ll i=;i<=n;++i)
{
ll t=i-w[i]-;
ll x=pre[i-]-(t>=?pre[t]:);
pre[i]=pre[i-]+(x>);
}
for(ll i=n-;i>=;--i)
{
ll t=i+w[i]+;
ll x=suf[i+]-(t<=n?suf[t]:);
suf[i]=suf[i+]+(r[i]=(x>));
}
ll ans=;
for(ll i=;i<=n;++i)ans+=pre[i-]*r[i];
return ans;
}
signed main()
{
//freopen("1.in","r",stdin);
n=read();m=read();
for(ll i=;i<=n;++i)
{
scanf("%s",a+);
for(ll j=;j<=m;++j)
{
R[i]=(R[i]*P+a[j])%mod;
C[j]=(C[j]*P+a[j])%mod;
}
}
printf("%lld\n",calc(n,R)*calc(m,C));
return ;
}

这题真的是精髓 manacher 的精髓 还是折纸的精髓 我 估计理解不深所以写的慢吧 以后要复习啊 光这道题就写了4h 完蛋了GG了。

T3 此题好题 思路非常的清奇 55分 n^2暴力 set维护 维护一个偏移量就可以结局不过+1的情况 查找的时候没思考清楚写挂了 正解是把这些数字放到trie树中然后搞一些事情 考虑+1的情况 把trie树上链为111111这一条链上所有节点都交换左右儿子即可。

复杂度logn 由于%2^30 那么如果存在最后一位也交换的话 相当于全部都变成0了符合取模。考虑^cnt在trie树上的体现普通对数字的体现是 如果cnt的某一位是0那么这个数字当前位不变 是1 的话这个数字当前位0 1 互换trie树上也是如此不过这个要考虑到所有的节点复杂度nlogn 因为是trie树每一个节点。trie树给我们带来的好处+1单次操作logn ^x这个操作nlogn 显然+法和^无法共存不妨+1直接修改^记全体偏移量。那么复杂的就是Qlogn+nlogn了

当然还有一个小问题 ^x)+1如何把1提到前面的问题 这个要从 x上进行考虑x如果当前位为1的话那么trie树之上全为1的那一条链的对应位经过x异或应该是0我们此时+1累计到这个0上就好了因为这个0才是真正的1.那么我们真实的链是什么呢(2^30-1)一开始全为1

经过x异或如果对应位是1的话那么链应该是0对应位是0的话链应该是1 综上这条链为(2^30-1)^x 这条链就好了。

关于这样做的正确性:首先+1我们就是更改一条链交换其左右儿子^在前不妨假设^交换好了+1的话是刚才的链那么其实改变的就是cnt交换掉的东西我们直接改变cnt会交换掉的东西先+再^就显然成立了。

//#include<bits/stdc++.h>
#include<iostream>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<cctype>
#include<utility>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<deque>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<iomanip>
#include<stack>
#include<string>
#include<cstring>
#define INF 2000000000
#define ll long long
#define db double
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)>(y)?(y):(x))
#define mp(x,y) make_pair(x,y)
using namespace std;
char *fs,*ft,buf[<<];
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return f<?-x:x;
}
const int MAXN=,mod=<<;
int n,Q,id,cnt;
int tag;//异或标记
int a[MAXN<<];
int t[MAXN<<][],sz[MAXN<<];
inline void insert(int x)
{
int p=;x=x^tag;
for(int i=;i<=;++i)
{
int tn=(x>>i)&;
if(!t[p][tn])t[p][tn]=++id;
p=t[p][tn];
}
++sz[p];
}
inline void cancel(int x)
{
int p=;x=x^tag;
for(int i=;i<=;++i)
{
int tn=(x>>i)&;
p=t[p][tn];
}
--sz[p];
}
inline void modify()//寻找最小的i使得trie树上一坨都是1
//如果tag==0 直接找就好了 考虑tag!=0
//如何把^tag)+1转换成+1)^tag 看起来非常的抽象 不妨观察前者的操作、
//其实就是tag^(mod-1) 这一条链
{
int p=,qaq=tag^(mod-);
for(int i=;i<=;++i)
{
int tn=(qaq>>i)&;
swap(t[p][],t[p][]);
p=t[p][tn^];
if(!p)return;
}
}
inline void solve(int p,int sum,int w)
{
if(!p&&w!=)return;
if(sz[p])
{
for(int i=;i<=sz[p];++i)a[++cnt]=sum^tag;
return;
}
solve(t[p][],sum,w<<);
solve(t[p][],sum|w,w<<);
return;
}
int main()
{
//freopen("1.in","r",stdin);
n=read();Q=read();
for(int i=;i<=n;++i)insert(read());
for(int i=;i<=Q;++i)
{
int op,x;
op=read();if(op!=)x=read();
if(op==)insert(x);
if(op==)cancel(x);
if(op==)modify();
if(op==)tag=tag^x;
}
solve(,,);
sort(a+,a++cnt);
for(int i=;i<cnt;++i)printf("%d ",a[i]);
printf("%d\n",a[cnt]);
return ;
}

ZROI 提高十连测 Day1的更多相关文章

  1. ZROI 提高十连测 DAY3

    由于我不太会写 觉得从比赛开始就冷静分析.然后看完三道题心态有点爆炸没有紧扣题目的性质. 这个心态是不可取的尽量不要有畏难心理 不要草草的写暴力. LINK:[最长01子序列](http://zhen ...

  2. ZROI 提高十连测 DAY2

    总结:入题尽量快,想到做法要先证明是否正确是否有不合法的情况,是否和题目中描述的情景一模一样.    不要慌 反正慌也拿不了多少分,多分析题目的性质如果不把题目的性质分析出来的话,暴力也非常的难写,有 ...

  3. 提高十连测day3

    提高十连测day3 A 我们可以枚举两个 $ 1 $ 之间的相隔距离,然后计算形如 $ 00100100 \cdots $ 的串在原串中最⻓⼦序列匹配即可,复杂度 $ O(n^2) $ .寻找 $ S ...

  4. ZROI2019 提高十连测

    额 掰手指头一数 特么又是第三年十连测了= = 2017一场没打 那时候好像一场比赛也就100人左右 2018前几场还都好好补了 后来开始放飞自我了 这时候一场有150人还多了 2019想让今年的No ...

  5. 正睿OI提高组十连测 day1 总结

    可能是最简单的一场比赛了吧,结果却打得这么差... T1是个找规律题,结果一开始愚蠢地找错了规律,然后又对拍,到1h多一点才过掉 然后看t2和t3,以为t2是个水题,t3也只要处理一下就好了,先写t2 ...

  6. 十连测Day1 题解

    A. 奥义商店 有一个商店,n个物品,每个物品有一个价格和一种颜色. 有m个操作,操作有两种,一种是修改一个位置的价格,另一种是购买,每次购买指定一个公差d和一个位置k,找到包含这个位置k公差为d的同 ...

  7. bzoj 5216 [Lydsy2017省队十连测]公路建设 线段树维护 最小生成树

    [Lydsy2017省队十连测]公路建设 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 93  Solved: 53[Submit][Status][ ...

  8. ZROI提高组模拟赛05总结

    ZROI提高组模拟赛05总结 感觉是目前为止最简单的模拟赛了吧 但是依旧不尽人意... T1 有一半的人在30min前就A掉了 而我花了1h11min 就是一个简单的背包,我硬是转化了模型想了好久,生 ...

  9. bzoj 5216: [Lydsy2017省队十连测]公路建设

    5216: [Lydsy2017省队十连测]公路建设 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 66  Solved: 37[Submit][St ...

随机推荐

  1. Python 之父说 Python 历史

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:鸿影洲冷 这篇文章主要内容来源于 Python 编程语言的最初设计者 ...

  2. Google 出品的 Java 编码规范,强烈推荐,既权威又科学

    这份文档是 Google Java 编程风格规范的完整定义.当且仅当一个Java源文件符合此文档中的规则, 我们才认为它符合Google的Java编程风格.原文:google.github.io/st ...

  3. ubuntu docker安装与部署java,mysql,nginx镜像

    docker 安装与部署java,mysql,nginx docker 配置 安装docker $ sudo apt-get remove docker docker-engine docker.io ...

  4. python 读取指定文件夹中的指定文件类型的文件名

    import numpy as np import os path = 'F:\\wenjian'#指定文件所在路径 filetype ='.csv'#指定文件类型 def get_filename( ...

  5. python 迭代器(二):迭代器基础(二)可迭代的对象与迭代器的对比

    可迭代的对象 如果对象实现了能返回迭代器的 __iter__ 方法,那么对象就是可迭代的. 序列都可以迭代:实现了 __getitem__ 方法,而且其参数是从零开始的索引,这种对象也可以迭代. &g ...

  6. windows python的多进程

    最近打比赛,apply操作极慢,队友使用了线程池,用多核开辟多线程跑,加速. 在阿里平台上,都没问题. 我是win10系统+jupyter notebook 多线程那个模块运行,会显示一直运行,p.c ...

  7. bzoj4318OSU!*

    bzoj4318OSU! 题意: 一个长度为n的序列,每个元素有一定概率是1,不是1就是0.连续x个1可以贡献x^3的分数,问期望分数. 题解: 期望dp.f1[i]表示连续到i的期望长度,f2[i] ...

  8. 通过server酱实现定时推送天气情况,再不用担心你的糊涂蛋女友忘带伞了~~

    昨天菜鸟小白给大家留了一个课后作业,如何实现天气的定时推送.有没有小伙伴做出来答案呢?今天菜鸟小白给大家分享我的实现方式吧.这个是我今天整的程序流程图,昨天我们还只是实现了中间的通过和风天气API获取 ...

  9. 一个简单的Maven小案例

    Maven是一个很好的软件项目管理工具,有了Maven我们不用再费劲的去官网上下载Jar包. Maven的官网地址:http://maven.apache.org/download.cgi 要建立一个 ...

  10. 30页软件测试人面试宝典文档资料,助你拿下了百度、美团、字节跳动、小米等大厂的offer【内含答案】

    前言:看了一下桌边的日历,新的6月,已经过去5天了.明天又是周六了,大家准备怎么度过呢?趁着大家周末给大家分享一个软件测试工程师面试题汇总. 拿到大厂的offer一直是软件测试朋友的一个目标,我是如何 ...