D1T1.玩具谜题

题目链接

直接模拟就好了……water。

 #include<cstdio>
int n,m,a,s,ans;
struct node{char name[];int dir;}x[];
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<n;i++)scanf("%d%s",&x[i].dir,x[i].name);
while(m--)
{
scanf("%d%d",&a,&s);
if(a==x[ans].dir)ans-=s;
else ans+=s;
if(ans<)ans+=n;
ans%=n;
}
printf("%s",x[ans].name);
return ;
}

D1T2.天天爱跑步

题目链接

因为太菜了,至今不会这道题……先扔题目链接,以后再回来把坑填了(flag 我回来填坑辣

s→t的路径可以拆成s→lca和lca→t两条路径,草稿纸上画一画可以推出两条公式:如果点i可以被检测到,则在s→lca这条路径上:deep[i]+w[i]=deep[s];或者在lca→t这条路径上:deep[i]-w[i]=deep[t]-way(路径长度)。

剩下的……写了比较详细的代码注释。

 #include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int N=;
int n,m,u,v,cnt,s,t,anc,way;
int time[N],ans[N],up[N*],dn[N*],c[N];//注意up数组和dn数组都要开两倍
int first[N],deep[N],f[N][];
struct edge{int to,next;}e[N*];//边表开两倍
vector<int>q1[N],q2[N],q3[N];
int read()
{
int x=,f=;char c=getchar();
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
return x*f;
}
void ins(int u,int v){cnt++;e[cnt].to=v;e[cnt].next=first[u];first[u]=cnt;}
void dfs(int x)
{
for(int i=first[x];i;i=e[i].next)
{
int to=e[i].to;
if(deep[to])continue;//节点to已出现过
deep[to]=deep[x]+;
f[to][]=x;//to的父亲为x
dfs(to);
}
}
int lca(int ri,int rj)//倍增求最近公共祖先
{
if(deep[ri]<deep[rj])swap(ri,rj);
int d=deep[ri]-deep[rj];
for(int i=;(<<i)<=d;i++)
if((<<i)&d)ri=f[ri][i];
if(ri==rj)return ri;
for(int i=;i>=;i--)
if((<<i)<=deep[rj]&&f[ri][i]!=f[rj][i])
ri=f[ri][i],rj=f[rj][i];
return f[ri][];
}
void DFS(int x,int last)
{
//向上的桶一律加N是为了防止减的时候出现负数
int u=dn[deep[x]+time[x]],v=up[deep[x]-time[x]+N],sz;
dn[deep[x]]+=c[x];//节点x作为s出现
sz=q1[x].size();
for(int i=;i<sz;i++)up[q1[x][i]+N]++;//点x作为t出现
for(int i=first[x];i;i=e[i].next)if(e[i].to!=last)DFS(e[i].to,x);
ans[x]=dn[deep[x]+time[x]]+up[deep[x]-time[x]+N]-u-v;
//详见之前提到的公式,以及记得减去旧值
sz=q2[x].size();
for(int i=;i<sz;i++){dn[q2[x][i]]--;if(q2[x][i]==deep[x]+time[x])ans[x]--;}
//如果是在lca处被检测到,记得减去重复情况
sz=q3[x].size();
for(int i=;i<sz;i++)up[q3[x][i]+N]--;
//dfs退出lca时,更新两个桶
}
int main()
{
n=read();m=read();
for(int i=;i<n;i++)
{
u=read();v=read();
ins(u,v);ins(v,u);
}
deep[]=;//会影响后面dfs的判断
dfs();
for(int j=;j<=;j++)
for(int i=;i<=n;i++)
f[i][j]=f[f[i][j-]][j-];//递推出f数组
for(int i=;i<=n;i++)time[i]=read();
for(int i=;i<=m;i++)
{
s=read();t=read();
anc=lca(s,t);//最近公共祖先
way=deep[s]+deep[t]-*deep[anc];//路径长度
c[s]++;//节点s作为起点出现的次数+1
q1[t].push_back(deep[t]-way);
q2[anc].push_back(deep[s]);
q3[anc].push_back(deep[t]-way);
//前面提到的两条公式:
//在s→lca这条路径上:deep[i]+w[i]=deep[s];
//在lca→t这条路径上:deep[i]-w[i]=deep[t]-way;
//一个节点对ans的贡献从LCA开始,所以存在LCA的队列里
}
DFS(,);
for(int i=;i<=n;i++)printf("%d ",ans[i]);
return ;
}

D1T3.换教室

题目链接

最短路+期望dp。

数组dp[i][j][k]代表当前进行到第i个时间段,已经更换了j门课程;若k=0则代表当前时间段不更换教室,k=1则代表当前时间段更换教室。

记得最后再循环一下dp[n][j][k],输出最优解。

 #include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=;
const double inf=1e15;
int n,m,v,e,a,b,c[N],d[N];
double w,k[N],dp[N][N][],dis[N][N];
int read()
{
int x=,f=;char c=getchar();
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
return x*f;
}
void floyd()
{
for(int k=;k<=v;k++)
for(int i=;i<=v;i++)
for(int j=;j<=v;j++)
dis[i][j]=dis[j][i]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
int main()
{
n=read();m=read();v=read();e=read();
for(int i=;i<=n;i++)c[i]=read();
for(int i=;i<=n;i++)d[i]=read();
for(int i=;i<=n;i++)scanf("%lf",&k[i]);
for(int i=;i<=v;i++)
for(int j=;j<=v;j++)
if(i!=j)dis[i][j]=inf;
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
dp[i][j][]=dp[i][j][]=inf;
for(int i=;i<=e;i++)
a=read(),b=read(),scanf("%lf",&w),dis[a][b]=dis[b][a]=min(dis[a][b],w);
floyd();
dp[][][]=;dp[][][]=;
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
{
if(j==)dp[i][j][]=min(dp[i][j][],dp[i-][j][]+dis[c[i-]][c[i]]);
else
{
dp[i][j][]=min(dp[i][j][],dp[i-][j][]+dis[c[i-]][c[i]]);
dp[i][j][]=min(dp[i][j][],dp[i-][j][]+dis[d[i-]][c[i]]*k[i-]+dis[c[i-]][c[i]]*(-k[i-]));
dp[i][j][]=min(dp[i][j][],dp[i-][j-][]+dis[c[i-]][d[i]]*k[i]+dis[c[i-]][c[i]]*(-k[i]));
dp[i][j][]=min(dp[i][j][],dp[i-][j-][]+dis[c[i-]][c[i]]*(-k[i-])*(-k[i])+dis[c[i-]][d[i]]*(-k[i-])*k[i]
+dis[d[i-]][c[i]]*k[i-]*(-k[i])+dis[d[i-]][d[i]]*k[i-]*k[i]);
}
}
double ans=inf;
for(int i=;i<=m;i++)
{
ans=min(ans,dp[n][i][]);
ans=min(ans,dp[n][i][]);
}
printf("%.2lf",ans);
return ;
}

D2T1.组合数问题

题目链接

杨辉三角打个表,然后前缀和优化优化(get到新姿势

 #include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=;
long long n,m,t,k,f[N][N],sum[N][N];
long long read()
{
long long x=,f=;char c=getchar();
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
return x*f;
}
int main()
{
t=read();k=read();
for(int i=;i<N;i++)f[i][]=;
for(int i=;i<N;i++)
for(int j=;j<=i;j++)
{
f[i][j]=(f[i-][j]+f[i-][j-])%k;
if(!f[i][j])sum[i][j]=;
sum[i][j]+=sum[i][j-];
}
while(t--)
{
long long ans=;
n=read();m=read();
for(long long i=;i<=n;i++)
ans+=sum[i][min(m,i)];
printf("%lld\n",ans);
}
return ;
}

D2T2.蚯蚓

题目链接

维护三个队列:q1是原数列(先从大到小sort一波),q2是砍完之后的前段,q3是砍完之后的后段(依据题意易得,q2、q3单调递减)。每次从三个队列的队头元素取出最大的一个进行切断操作并在队列中删去它,再将砍完后生成的两个新数分别存入q2、q3。

至于每次操作完增加的长度……直接用时间算就好了✔

 #include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=;
const int M=;
double p;
int h1=,h2=,t2,h3=,t3;
long long n,m,q,u,v,t;
long long q1[N],q2[M],q3[M];
long long read()
{
long long x=,f=;char c=getchar();
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
return x*f;
}
bool cmp(long long a,long long b){return a>b;}
long long get(int tim)
{
long long x=-0x3f3f3f3f3f3f3f3f;
if(h1<=n&&q1[h1]>x)x=q1[h1];
if(h2<=t2&&q2[h2]>x)x=q2[h2];
if(h3<=t3&&q3[h3]>x)x=q3[h3];
if(h1<=n&&x==q1[h1])h1++;
else if(h2<=t2&&x==q2[h2])h2++;
else h3++;
return x+(tim-)*q;
}
int main()
{
n=read();m=read();q=read();u=read();v=read();t=read();p=1.0*u/v;
for(int i=;i<=n;i++)q1[i]=read();
sort(q1+,q1+n+,cmp);
for(int i=;i<=m;i++)
{
long long k=get(i);
if(i%t==)printf("%lld ",k);
long long k1=floor(k*p),k2=k-k1;
q2[++t2]=k1-q*i;q3[++t3]=k2-q*i;//注意-q*i!
}
printf("\n");
for(int i=;i<=n+m;i++)
{
long long k=get(m+);
if(i%t==)printf("%lld ",k);
}
return ;
}

D3T3.愤怒的小鸟

题目链接

状压dp……注意精度问题。

f[i][j]代表当第i只小猪与第j只小猪配对时,小鸟的飞行轨迹可以消灭的小猪的状态。处理完就先枚举当前状态,然后枚举第一只尚未配对的小猪,再枚举与其配对的小猪,直接dp。

注意:有可能一只小鸟只消灭了一只小猪。

 #include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int T,n,m,id[],f[][],dp[<<];
double a,b,x[],y[];
bool pan(double x,double y){return fabs(x-y)<1e-;}
void solve()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)scanf("%lf%lf",&x[i],&y[i]);
memset(f,,sizeof(f));
for(int i=;i<=n;i++)
for(int j=i+;j<=n;j++)
{
if(pan(x[i],x[j]))continue;
a=(y[j]/x[j]-y[i]/x[i])/(x[j]-x[i]);
if(a>=)continue;
b=y[i]/x[i]-a*x[i];
int t=;
for(int k=;k<=n;k++)
if(pan(a*x[k]+b,y[k]/x[k]))t+=id[k];
f[i][j]=t;
}
memset(dp,0x3f,sizeof(dp));dp[]=;
for(int i=;i<(<<n);i++)
for(int j=;j<=n;j++)
{
if(i&id[j])continue;
for(int k=j+;k<=n;k++)
dp[i|f[j][k]]=min(dp[i|f[j][k]],dp[i]+);
dp[i|id[j]]=min(dp[i|id[j]],dp[i]+);//注意处理一只小鸟只消灭一只小猪的情况!
}
printf("%d\n",dp[(<<n)-]);
}
int main()
{
for(int i=;i<=;i++)id[i]=<<(i-);
scanf("%d",&T);
while(T--)solve();
return ;
}

【noip 2016】提高组的更多相关文章

  1. noip 2016提高组D2T1 problem

    我们可以先预处理一下组合数模K的值,然后我们可以发现对于答案ji[n][m],可以发现递推式ji[i][j]=ji[i-1][j]+ji[i][j-1]-ji[i-1][j-1]并对于Cij是否%k等 ...

  2. noip 2016 提高组题解

    前几天写的那个纯属搞笑.(额,好吧,其实这个也不怎么正经) 就先说说day2吧: T1:这个东西应该叫做数论吧. 然而我一看到就照着样例在纸上推了大半天(然而还是没有看出来这东西是个杨辉三角) 然后就 ...

  3. noip 2016 提高组总结(不是题解)

    小弱鸡杨树辰是第一次参加像noip这样的高大上的比赛,于是他非常,非常,非常激动. 当他第二天考完试后,他正在yy自己的分数:day1T1应该是a掉了,T2写了个30分的暴力,T3也是个40分的暴力, ...

  4. NOIP 2016 提高组 复赛 Day2T1==洛谷2822 组合数问题

    题目描述 组合数表示的是从n个物品中选出m个物品的方案数.举个例子,从(1,2,3) 三个物品中选择两个物品可以有(1,2),(1,3),(2,3)这三种选择方法.根据组合数的定 义,我们可以给出计算 ...

  5. NOIP 2008提高组第三题题解by rLq

    啊啊啊啊啊啊今天已经星期三了吗 那么,来一波题解吧 本题地址http://www.luogu.org/problem/show?pid=1006 传纸条 题目描述 小渊和小轩是好朋友也是同班同学,他们 ...

  6. [NOIp 1998 提高组]Probelm 2 连接多位数【2011百度实习生笔试题】

    /*====================================================================== [NOIp 1998 提高组]Probelm 2 连接 ...

  7. NOIP 2014 提高组 题解

    NOIP 2014 提高组 题解 No 1. 生活大爆炸版石头剪刀布 http://www.luogu.org/problem/show?pid=1328 这是道大水题,我都在想怎么会有人错了,没算法 ...

  8. NOIP 2001 提高组 题解

    NOIP 2001 提高组 题解 No 1. 一元三次方程求解 https://vijos.org/p/1116 看见有人认真推导了求解公式,然后猥琐暴力过的同学们在一边偷笑~~~ 数据小 暴力枚举即 ...

  9. 最优贸易 NOIP 2009 提高组 第三题

    题目描述 C 国有 n 个大城市和 m 条道路,每条道路连接这 n 个城市中的某两个城市.任意两个 城市之间最多只有一条道路直接相连.这 m 条道路中有一部分为单向通行的道路,一部分 为双向通行的道路 ...

  10. NOIP 2006 提高组 t1 能量项链

    题目描述 在Mars星球上,每个Mars人都随身佩带着一串能量项链.在项链上有N颗能量珠.能量珠是一颗有头标记与尾标记的珠子,这些标记对应着某个正整数.并且,对于相邻的两颗珠子,前一颗珠子的尾标记一定 ...

随机推荐

  1. django pymysql

    此处django版本为1.11.13 设置setting.py DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NA ...

  2. centos7安装mha4mysql

    mysql搭建mha需要用的两个rpm包.(manager包和node包) 下载地址:https://download.csdn.net/download/dajdajdajdaj/10603389 ...

  3. Yii2 如何输出 sql 语句?

    可以用 $model->find()->createCommand()->getRawSql(); 不能带 all(). find() 它的 返回值类型是 yii\db\Active ...

  4. dbForge Studio for MySQL V8.0 Enterprise

    上篇文章:JetBrains全家桶破解思路(最新更新:2018-12-24) 最适合从SQLServer转向MySQL的人使用(用起来基本上差不多) 最适合Net开发人员的MySQL IDE (不装V ...

  5. 如何 通过 userAgent 区别微信小程序

    微信内置浏览器: 微信小程序: 有micromessenger是微信内置浏览器,有micromessenger和miniprogram的是微信小程序.  (ios不适用) if(navigator.u ...

  6. BZOJ3512 DZY Loves Math IV

    解:这又是什么神仙毒瘤题...... 我直接把后面那个phi用phi * I = id反演一波,得到个式子,然后推不动了...... 实际上第一步我就大错特错了.考虑到n很小,我们有 然后计算S,我们 ...

  7. 第一篇-Win10打开txt文件出现中文乱码

    如果刚开始安装的是英文的Win10系统,那么打开txt文件时很容易出现乱码问题.包括打开cmd窗口,也是不能显示中文的.当然,麻烦的处理方法是: 在cmd中想要显示中文:先输入chcp 936,之后中 ...

  8. 第三十二篇-NavigationView导航抽屉的使用

    效果图: 导航抽屉所用到的布局是DrawerLayout,可以在里面添加一个线性布局和TextView组件,TextView组件的文本信息就是"主页面".然后和线性布局平行添加一个 ...

  9. P2602 [ZJOI2010]数字计数

    https://www.luogu.org/problemnew/show/P2602 数位dp #include <bits/stdc++.h> using namespace std; ...

  10. webDriver文档阅读笔记

    一些雷 浏览器版本和对应的Driver的版本是一一对应的,有时候跑不起来,主要是因为driver和浏览器版本对不上. e.g: chrome和driver版本映射表:https://blog.csdn ...