noip模拟35[第一次4题·裂了]
noip模拟35 solutions
这是我第一次这么正式的考四个题,因为这四个题都出自同一个出题人,并不是拼盘拼出来的。
但是考得非常的不好,因为题非常难而且一直想睡觉。。
有好多我根本就不会的算法,比如说笛卡尔树,时至今日我还是不会
对我来说好像并不是一个很大的提升,因为好多题我不能只看着题解改出来
总是要问别人。。。。。我好菜啊好菜啊好菜啊
T1 玩游戏
其实这个题我在考场上的时候已经想到了正解的一半,
一眼看过去这就是个贪心,我就在草稿纸上手推贪心策略,推了半天发现到了最小值就走不动了
没有发现还可以从左右两端向中间贪心,于是这个题就做完了
我们从k位置将整个序列分成两个块,分别对两个块统计前缀和
每次寻找下一个比当前值小的值并向这个位置贪心,一直贪心到最小值
再从这个前缀和数组的最后往前贪心,一样贪到最小值
如果都能到达最小值,那么就合法,反之不合法。。
AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
const int N=1e5+5;
int T,n,k;
ll a[N],b[N],cb,c[N],cc;
ll prb[N],prc[N];
int nxb[N],nxc[N];
signed main(){
scanf("%d",&T);
while(T--){
/*memset(prb,0,sizeof(prb));
memset(prc,0,sizeof(prc));*/
memset(nxb,0,sizeof(nxb));
memset(nxc,0,sizeof(nxc));
scanf("%d%d",&n,&k);
for(re i=1;i<=n;i++)scanf("%lld",&a[i]);
c[cc=1]=0;for(re i=k+1;i<=n;i++)c[++cc]=a[i];
b[cb=1]=0;for(re i=k;i>1;i--)b[++cb]=a[i];
for(re i=1;i<=cb;i++)prb[i]=prb[i-1]+b[i];
for(re i=1;i<=cc;i++)prc[i]=prc[i-1]+c[i];
ll mn=prb[1],who=1,mb,mc;;
for(re i=2;i<=cb;i++)if(prb[i]<=mn){nxb[who]=i;who=i;mn=prb[i];}
mn=prb[cb];who=cb;
for(re i=cb-1;i>=1;i--)if(prb[i]<mn){nxb[who]=i;who=i;mn=prb[i];}
mn=prc[1];who=1;
for(re i=2;i<=cc;i++)if(prc[i]<=mn){nxc[who]=i;who=i;mn=prc[i];}
mn=prc[cc];who=cc;
for(re i=cc-1;i>=1;i--)if(prc[i]<mn){nxc[who]=i;who=i;mn=prc[i];}
//for(re i=1;i<=cb;i++)cout<<prb[i]<<" ";cout<<endl;
//for(re i=1;i<=cc;i++)cout<<prc[i]<<" ";cout<<endl;
int x=1,y=1;
bool flag=false;
if(prb[cb]+prc[cc]>0){
printf("No\n");continue;
}
while(nxb[x]||nxc[y]){
//cout<<x<<" "<<y<<endl;
flag=false;
for(re i=x+1;i<=nxb[x];i++)
if(prb[i]+prc[y]>0){
flag=true;
break;
}
if(!nxb[x])flag=true;
if(flag){
flag=false;
for(re i=y+1;i<=nxc[y];i++)
if(prb[x]+prc[i]>0){
flag=true;
}
if(!nxc[y])flag=true;
if(flag)break;
else y=nxc[y];
flag=false;continue;
}
x=nxb[x];flag=false;
}
if(flag){
printf("No\n");continue;
}
x=cb;y=cc;
while(nxb[x]||nxc[y]){
//if(x!=0)cout<<x<<" "<<nxb[x]<<" "<<y<<" "<<nxc[y]<<endl;
flag=false;
if(nxb[x]){
//cout<<nxb[x]<<endl;
for(re i=x-1;i>=nxb[x];i--)
if(prb[i]+prc[y]>0){
flag=true;
break;
}
}
else flag=true;
//cout<<flag<<endl;
if(flag){
flag=false;
if(nxc[y]){
for(re i=y-1;i>=nxc[y];i--)
if(prb[x]+prc[i]>0){
flag=true;
}
}
else flag=true;
//cout<<flag<<endl;
if(flag)break;
else y=nxc[y];
flag=false;continue;
}
x=nxb[x];flag=false;
}
if(flag){
printf("No\n");continue;
}
printf("Yes\n");
}
}
T2 排列
这个我是真的不知道怎么做,所以直接弃掉了。
所以说我已经发现了一个规律,对于这种随机搞出来的方案题
一般都是直接dp,而且是啥都不在乎的dp,就暴力转移就完事了
其实对于这个题我们完全可以直接全排列做的。。。。。。。爬
设dp[i][j][0/1][0/1]表示前i个点,消了j次能够只剩1个的方案数
你发现我这个东西转移的时候只能去分别枚举左右区间需要的次数,
这样的话,你就得有四层循环,一层枚举i,一层枚举j,一层枚举当前层的最大值位置
还有一层枚举两个子区间的j,
伪代码
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=1;k<=n;k++)
for(int jj=1;jj<j;j++){
dp[i][j][0/1][0/1]=dp[k-1][j-1][0/1][0/1]*dp[i-k][jj][0/1][0/1];
dp[i][j][0/1][0/1]=dp[k-1][jj][0/1][0/1]*dp[i-k][j-1][0/1][0/1];
}
此处省略许多细节。。。。。看AC_code
这样的话,你不T谁T,TTTTTTTTTTTTTTTTTTTTTTTTT飞了好吧
这样你发现这个转移好像并不是那么严谨,许多的转移都是同一个形式,
前缀和优化就是最好的选择,毕竟方程都是差不多的,
那么前缀和优化之后的方程就表示至多消j步的方案数,转移仍然是一样的
AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
const int N=1005;
ll n,m,mod;
ll dp[N][N][2][2];
ll c[N][N];
signed main(){
scanf("%lld%lld%lld",&n,&m,&mod);
for(re i=0;i<=m;i++)dp[0][i][0][0]=dp[0][i][0][1]=dp[0][i][1][0]=dp[0][i][1][1]=1;
c[0][0]=1;c[1][0]=1;c[1][1]=1;
for(re i=2;i<=n;i++){
c[i][0]=1;c[i][i]=1;
for(re j=1;j<i;j++){
c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
//cout<<c[i][j]<<" ";
}
//cout<<endl;
}
for(re i=1;i<=n;i++){
for(re j=1;j<=m;j++){
for(re k=1;k<=i;k++){
dp[i][j][0][0]=(dp[i][j][0][0]+dp[k-1][j][0][1]*dp[i-k][j][1][0]%mod*c[i-1][k-1])%mod;
dp[i][j][0][1]=(dp[i][j][0][1]+dp[k-1][j][0][1]*dp[i-k][j-1][1][1]%mod*c[i-1][k-1])%mod;
dp[i][j][1][0]=(dp[i][j][1][0]+dp[k-1][j-1][1][1]*dp[i-k][j][1][0]%mod*c[i-1][k-1])%mod;
dp[i][j][1][1]=(dp[i][j][1][1]+(dp[k-1][j][1][1]*dp[i-k][j][1][1]-(dp[i-k][j][1][1]-dp[i-k][j-1][1][1])*(dp[k-1][j][1][1]-dp[k-1][j-1][1][1])%mod)%mod*c[i-1][k-1])%mod;
}
}
}
ll ans=(dp[n][m][0][0]+mod-dp[n][m-1][0][0])%mod;
printf("%lld",ans);
}
T3 最短路
这个题我好像是用yubai的乱搞做法过去的,好像也是正解,反正跑的还挺快
简单来说就是一个分层图,也不能说是分层,就是两个点一起走
然后对于重复的点来说就直接用一个bitset维护就好了,其实bool数组也是可以的
好像正确性并不能保证,对于当前的两个点来说后面可能会经过一个点
使得当前的点的较大值能够得到最优解,所以这个题我就弃了
放上我的假代码。。。。
AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
const int N=255;
const int M=255*255;
int n,m,val[N];
struct EDGE{
int to[M],nxt[M],head[N],rp;
EDGE(){}
void add_edg(int x,int y){
to[++rp]=y;
nxt[rp]=head[x];
head[x]=rp;
}
}be,af;
int ans[N][N];
bitset<N> bit[N][N];
struct node{
int x,y,dis;
node(){}
node(int a,int b,int c){
x=a;y=b;dis=c;
}
bool operator < (node a)const{
return dis>a.dis;
}
};
priority_queue<node> q;
bool vis[N][N];
void dij(){
bit[1][1].set(1);
ans[1][1]=val[1];
q.push(node(1,1,val[1]));
while(!q.empty()){
int x=q.top().x;
int y=q.top().y;
int dis=q.top().dis;q.pop();
if(vis[x][y])continue;
vis[x][y]=true;
//cout<<x<<" "<<y<<" "<<dis<<endl;
for(re i=be.head[x];i;i=be.nxt[i]){
int tx=be.to[i];
int tmp=dis;
if(bit[x][y][tx]==0)tmp+=val[tx];
if(tmp>=ans[tx][y])continue;
bit[tx][y]=bit[x][y];
bit[tx][y].set(tx);
ans[tx][y]=tmp;
q.push(node(tx,y,tmp));
}
for(re i=af.head[y];i;i=af.nxt[i]){
int ty=af.to[i];
int tmp=dis;
if(bit[x][y][ty]==0)tmp+=val[ty];
if(tmp>=ans[x][ty])continue;
bit[x][ty]=bit[x][y];
bit[x][ty].set(ty);
ans[x][ty]=tmp;
q.push(node(x,ty,tmp));
}
}
}
signed main(){
scanf("%d%d",&n,&m);
for(re i=1;i<=n;i++)scanf("%d",&val[i]);
for(re i=1;i<=m;i++){
int x,y;scanf("%d%d",&x,&y);
be.add_edg(x,y);
af.add_edg(y,x);
}
memset(ans,0x3f,sizeof(ans));
dij();//cout<<ans[n][n]<<endl;
if(ans[n][n]==0x3f3f3f3f)printf("-1");
else printf("%d",ans[n][n]);
}
当然我们是有办法搞到这个题的正确性的,把continue删掉就好了
只不过你会T,T到飞起。
T4 矩形
我走了,我走了,我不会,我写不出来,我根本不会打。。。。。
noip模拟35[第一次4题·裂了]的更多相关文章
- noip模拟23[联·赛·题]
\(noip模拟23\;solutions\) 怎么说呢??这个考试考得是非常的惨烈,一共拿了70分,为啥呢 因为我第一题和第三题爆零了,然后第二题拿到了70分,还是贪心的分数 第一题和第二题我调了好 ...
- Noip模拟考第三题——饥饿游戏
饥饿游戏 (hungry.pas/c/cpp) [问题描述] Chanxer饿了,但是囊中羞涩,于是他去参加号称免费吃到饱的“饥饿游戏”. 这个游戏的规则是这样的,举办者会摆出一排 个食物,希望你能够 ...
- Noip模拟35 2021.8.10
考试题目变成四道了,貌似确实根本改不完... 不过给了两个小时颓废时间确实很爽(芜湖--) 但是前几天三道题改着不是很费劲的时候为什么不给放松时间, 非要在改不完题的时候颓?? 算了算了不碎碎念了.. ...
- noip模拟4[随·单·题·大佬]
woc woc woc难斩了人都傻了 害上来先看T1,发现这不就是一个小期望嘛(有啥的)真是!!打算半个小时秒掉 可是吧,读着读着题面,发现这题面有大问题,后来去找老师,还是我nb给题挑错, ...
- NOIP 模拟 $13\; \text{玄学题}$
题解 题如其名,是挺玄学的. 我们发现每个值是 \(-1\) 还是 \(1\) 只与它的次数是奇是偶有关,而 \(\sum_j^{j\le m}d(i×j)\) 又只与其中有多少个奇数有关 对于 \( ...
- NOIP 模拟 $13\; \text{工业题}$
题解 本题不用什么推式子,找规律(而且也找不出来) 可以将整个式子看成一个 \(n×m\) 矩阵 考虑 \(f_{i,j}\),它向右走一步给出 \(f_{i,j}×a\) 的贡献,向下走一步给出 \ ...
- NOIP模拟13「工业题·卡常题·玄学题」
T1:工业题 基本思路 这题有一个重要的小转化: 我们将原来的函数看作一个矩阵,\(f(i,j-1)*a\)相当于从\(j-1\)向右走一步并贡献a,\(f(i-1,j)*b\)相当于从\(i-1 ...
- NOIP模拟 35
int乘爆见祖宗 难得地T3暴力打满 T1T2思路也都正确 然而T2没看出一个int乘爆直接滚粗.. 这谁抗的住啊... 跟天皇说我差点就rank1了 换来的只有一张奸笑的大脸和一堆垃圾的嘲讽 真巨啊 ...
- noip模拟35
A. 玩游戏 考场做法用双指针向两侧更新,当左段点左移一位时,如果右端点不满足条件,则跳回肯定满足的位置.复杂度玄学 题解做法是类似最长子段和,如果有一个区间和为负,则维护的指针跳过去即可 B. 排列 ...
随机推荐
- 33、jQuery介绍
33.1.jQuery是什么: (1)jQuery由John Resig创建,至今已吸引了来自世界各地的众多 javascript 高手加入其team. (2)jQuery是继prototype之后又 ...
- 浅谈最长上升子序列(O(n*logn)算法)
今天GM讲了最长上升子序列的logn*n算法,但没讲思路... 我看了篇博客,发现-- 说的有道理!!! 首先,举例子: a[7]={1,2,4,3,6,7,5}(假设以1开头) 很明显,LIS=5: ...
- Elasticsearch的配置学习笔记
文/朱季谦 Elasticsearch是一个基于Lucene的搜索服务器.它提供一个分布式多用户能力的全文搜索引擎,基于RESTful web接口,Elasticsearch是用Java语言开发的. ...
- keycloak~OIDC&OAuth2&自定义皮肤
1 OpenID & OAuth2 & SAML 1.1 相关资料 https://github.com/keycloak/keycloak https://www.keycloak. ...
- python二进制读写及特殊码同步
python对二进制文件的操作需要使用bytes类,直接写入整数是不行的,如果试图使用f.write(123)向文件中以二进制写入123,结果提示参数不是bytes类型. import os impo ...
- linux学习之路第三天(vim和vi使用)
vi和vim编辑器 vi和vim的三种常见模式 1.正常模式 在正常模式下,我们可以使用快捷键 以vim打开一个档案就直接进入一般模式了(这是默认的模式).在这个模式中,你可以使用 上下左右按键来移动 ...
- mybatis框架的第二天
一.mybatis的基础crud的操作 先在接口中,写对应的方法名称,返回类型,访问符. 之后在映射配置文件中,写具体的实现 二.mybati中crud的细节 1.模糊查询 这是接口中 这是xml中 ...
- WPF教程十四:了解元素的渲染OnRender()如何使用
上一篇分析了WPF元素中布局系统的MeasureOverride()和ArrangeOverride()方法.本节将进一步深入分析和研究元素如何渲染它们自身. 大多数WPF元素通过组合方式创建可视化外 ...
- 构造函数 析构函数的区别与联系 C#
构造函数 __construct:是在对象被创建是自动调用的方法,用来完成初始化操作 构造函数有以下特点:1.构造函数的名字必须与类名相同:2.构造函数可以有任意类型的参数,但不能具有返回类型:3.定 ...
- ScienceDirect内容爬虫
爬虫违法,本贴方法只限于个人对数据的分析使用,其爬虫程序已作相关设置,以减小服务器压力.不适宜长期使用. 一.前期准备 1.使用chrome打开ScienceDirect网站(https://www. ...