NOIP模拟题 [LIS][建图][递推][容斥]
来源:互联网 发布:智能数据盒子 编辑:程序博客网 时间:2024/05/20 09:22
正确评估题目难度。
T1:
题意:
给定一棵树,求使得每一个节点的左子树任意值都比当前节点值小,右子树任意值都比当前节点大所需要的最小改动点数。
分析:
首先对于这种神奇的递归定义,我们通过传递大小关系可以发现,通过上推我们可以确定任意两点之间的大小关系,然后很容易想到把树上的点排序。
所以如果先忽略掉“严格递增”和“可能中间不能加数”,这道题显然可以直接贪心减去LIS。
那么这种算法会遇到什么问题呢,显然就是可能有的序列中间是不能加数的!
那么怎么解决呢,很容易可以发现两个之间可以有的数是两数差
于是,当当当,算法出来了,就减一下就可以啦(其实也可以不减,每次比较,但是非常麻烦!预处理大法好!)
#include<cstdio>#include<iostream>#include<cmath>#include<cstdlib>#include<cstring>#include<string>#include<algorithm>#include<queue>#include<set>#include<map>#include<stack>#include<vector>#include<ctime>#define ll long long #define inf 2e18#define clr(x) memset(x,0,sizeof(x))#define maxen(x) memset(x,127,sizeof(x))#define maxer(x) memset(x,31,sizeof(x))#define minus(x) memset(x,-1,sizeof(x))#define each(i,n,m) for(int i=n;i<m;i++)#define eachrev(i,n,m) for(int i=n;i>m;i--)#define minn(a,b,c) min(a,min(b,c))#define maxx(a,b,c) max(a,max(b,c))#ifdef WIN32#define lld "%I64d"#else#define lld "%lld"#endif#define PROC "tree"//for(int i=1;i<=n;i++)//(double) (ll) LL (int)//(double)clock()/CLOCKS_PER_SECusing namespace std;const int Maxn=1e5+5;const int modd=1e9+7;int n,tmp1,tmp2,idx;int a[Maxn],rs[Maxn],ls[Maxn],rk[Maxn];ll f[Maxn];int cnt;int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f;}void init(){ n=read(); for(int i=1;i<=n;i++) a[i]=read(); for(int i=2;i<=n;i++){ tmp1=read();tmp2=read(); if(tmp2)rs[tmp1]=i; else ls[tmp1]=i; }}void dfs(int u){ if(ls[u])dfs(ls[u]); rk[++idx]=u; if(rs[u])dfs(rs[u]);}void work(){ dfs(1);f[cnt+1]=inf; for(int i=1;i<=n;i++){ a[rk[i]]-=i; int pos=upper_bound(f+1,f+cnt+2,a[rk[i]])-f; f[pos]=a[rk[i]]; if(pos>cnt){ cnt++;f[cnt+1]=inf; } } printf("%d",n-cnt);}void debug(){ //}int main(){ freopen(PROC".in","r",stdin); freopen(PROC".out","w",stdout); init(); work(); //debug(); return 0;}
T2:
题意:
给定一些数,求最后一个不能被组合出来的数。
分析:
久见此题,第一次真的写。
首先我们可以知道一个简单的判定,即如果一个大于等于最小单个数的区间都可以被组成的话,显然后面就都可以被组成了。
然后我们考虑“缩点”,因为mod最小数的值一样的点之间可以通过加上最小数到达,所以可以放在一个集合,只需要求出每个集合能被组成的最小数,则这个集合剩下的数都可以被组成。
即:根据相同性质减少工作量;
然后算出到每个集合的最短路(即最小能被组成的数)即可。
SPFA大法好,再写错我就去撞墙。
#include<cstdio>#include<iostream>#include<cmath>#include<cstdlib>#include<cstring>#include<string>#include<algorithm>#include<queue>#include<set>#include<map>#include<stack>#include<vector>#include<ctime>#define ll long long #define inf 2e8#define clr(x) memset(x,0,sizeof(x))#define maxen(x) memset(x,127,sizeof(x))#define maxer(x) memset(x,31,sizeof(x))#define minus(x) memset(x,-1,sizeof(x))#define each(i,n,m) for(int i=n;i<m;i++)#define eachrev(i,n,m) for(int i=n;i>m;i--)#define minn(a,b,c) min(a,min(b,c))#define maxx(a,b,c) max(a,max(b,c))#ifdef WIN32#define lld "%I64d"#else#define lld "%lld"#endif#define PROC "bullpen"//for(int i=1;i<=n;i++)//(double) (ll) LL (int)//(double)clock()/CLOCKS_PER_SECusing namespace std;const int Maxn=3e3+5;const int modd=1e9+7;int h[Maxn],usef[Maxn],f[Maxn],mapy[Maxn][Maxn];int n,m,tmp,idx,ans,s,p=2e9;queue<int>que;int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f;}int gcd(int a,int b){ return b==0?a:gcd(b,a%b);}void init(){ n=read(); m=read(); maxen(usef); maxer(f); maxer(mapy); for(int i=1;i<=n;i++){ tmp=read(); for(int j=0;j<=m;j++) if(j<tmp){h[tmp-j]=1;p=min(p,tmp-j);} else break; } s=p; for(int i=1;i<=3000;i++) if(h[i]){ s=gcd(i,s); usef[i%p]=min(usef[i%p],i); }}void work(){ if(s!=1||p==1){ printf("-1"); return; } for(int i=0;i<p;i++) for(int j=1;j<p;j++) if(i==j)mapy[i][j]=1; else if(usef[(j-i+p)%p]) mapy[i][j]=usef[(j-i+p)%p]; que.push(0);f[0]=0; while(!que.empty()){ int cur=que.front();que.pop(); for(int j=1;j<p;j++) if(f[j]>f[cur]+mapy[cur][j]){ f[j]=f[cur]+mapy[cur][j]; que.push(j); } } for(int i=1;i<p;i++) if(f[i]<=9e6) ans=max(ans,f[i]-p); printf("%d",ans);}void debug(){ //}int main(){ freopen(PROC".in","r",stdin); freopen(PROC".out","w",stdout); init(); work(); //debug(); return 0;}
T3:
题意:
求k种元素,每种N个,组成长【k,n】的,每种至少一个的序列的方案数。
分析:
考虑到每种都只要有一种,则可以很容易得到递推式。
然后考虑容斥原理,因为如果我们直接算,则可能会有一些相同的情况被重复计算,然后就减去了不成立的情况的情况(但是不会重复算,即不会对相同序列算两次!这是排列的性质,要想清楚啊!)
然后用容斥减去不成立的情况即可。
做递推不要玄学啊。
#include<cstdio>#include<iostream>#include<cmath>#include<cstdlib>#include<cstring>#include<string>#include<algorithm>#include<queue>#include<set>#include<map>#include<stack>#include<vector>#include<ctime>#define ll long long #define inf 2e8#define clr(x) memset(x,0,sizeof(x))#define maxen(x) memset(x,127,sizeof(x))#define maxer(x) memset(x,31,sizeof(x))#define minus(x) memset(x,-1,sizeof(x))#define each(i,n,m) for(ll i=n;i<m;i++)#define eachrev(i,n,m) for(ll i=n;i>m;i--)#define minn(a,b,c) min(a,min(b,c))#define maxx(a,b,c) max(a,max(b,c))#ifdef WIN32#define lld "%I64d"#else#define lld "%lld"#endif#define PROC "pearl"//for(ll i=1;i<=n;i++)//(double) (ll) LL (ll)//(double)clock()/CLOCKS_PER_SECusing namespace std;const ll Maxn=35;const ll modd=1234567891;ll t,n,k;ll ans;ll read(){ ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f;}void init(){ t=read();}ll qm(ll a,ll b){ ll ret=1; while(b){ if(b&1)(ret*=a)%=modd; (a*=a)%=modd; b>>=1; } return ret;}ll jc(ll n){ ll ret=1; for(ll i=1;i<=(ll)n;i++) (ret*=i)%=modd; return ret;}void work(){ for(ll i=1;i<=t;i++){ n=read(); k=read(); ans=0; ll flg=1; for(ll j=0;j<k-1;j++){ ll c=jc(k)*qm(jc(j),modd-2)%modd*qm(jc(k-j),modd-2)%modd; ll lc=qm(k-j,k)*(qm(k-j,n+1-k)%modd+modd-1LL)%modd*qm(k-j-1,modd-2)%modd; (ans+=(c*lc%modd)%modd*flg+modd)%=modd; flg=0-flg; } (ans+=(ll)k*(ll)(n-k+1)%modd*flg+modd)%=modd; printf(lld"\n",ans); }}void debug(){ //}int main(){ freopen(PROC".in","r",stdin); freopen(PROC".out","w",stdout); init(); work(); //debug(); return 0;}
- NOIP模拟题 [LIS][建图][递推][容斥]
- [NOIP模拟题][LIS][同余最短路][DP][矩阵快速幂][容斥原理]
- NOIP模拟题 2016.11.15 [LIS] [spfa] [同余最短路] [矩阵快速幂] [容斥原理] [数学]
- NOIP 模拟题 C17 [容斥原理]
- [NOIP模拟][LIS][数列映射][最短路][数论+图论][矩阵乘法][容斥原理]
- NOIP模拟题 [递推][DP][搜索]
- 【NOIP模拟题】【数学归纳法】【递推】【容斥原理】【等比数列求和】2016.11.15 第三题 小L的珍珠挂饰 题解
- NOIP模拟题[贪心][离散化][LIS]
- 【NOIP 模拟题】中位数(规律+递推)
- 【NOIP 模拟题】求和 (打表找规律+递推)
- 【NOIP 模拟题】[T2]one(递推)
- 【NOIP 模拟题】[T1](递推+乱搞)
- NOIP模拟题[递推][并查集][DP]
- NOIP模拟题 [递推][优化][dp][线段树][离散]
- NOIP-贪心,递推,枚举,模拟
- 【NOIP模拟题】【容斥原理】【数学归纳法】2016.11.18 第三题 题 题解
- 10.3 NOIP模拟赛 DP + 最小生成树 + 容斥
- [NOIP模拟][容斥原理][快速幂]Heal
- arguments的说明
- 导入环信Demo之'Execution failed for task 'apptransformClassesWithJarMergingForDebug'
- Oracle如何修改系统默认时间格式
- BZOJ2763: [JLOI2011]飞行路线
- 冒泡法实现链表排序
- NOIP模拟题 [LIS][建图][递推][容斥]
- 邮件服务器
- python try/except/finally
- RecyclerView的列表布局中match_parent失效的解决方法
- 获取mysql数据库中的自增主键属性值和非自增主键属性值的方法
- 动态代理
- sparkmllib线性回归源码学习
- 数据结构之串—关键词索引表
- Chat 聊天界面