NOI2013部分题解
Day 1
T1:向量内积
直接暴力有60。发现将n个向量合成$n\times d$的矩阵$A$,然后求$A\times A^T$,得到的矩阵包含了所有的答案。
先考虑$k=2$,将答案矩阵和全1矩阵比较,为0的地方就是答案。
回忆一个十分经典的问题:判断$A\times B$是否与$C$相等。
先随机一个行向量v,若$v\times(A\times B)=v\times A \times B\neq v\times C$,则直接返回$false$。多次随机,成功率为$1-(\frac12)^{times}$。
这种随机化算法通常用于:某对命题充分性和必要性仅具备一个,所以多做几次判定就能提高正确率。$Miller-Rabin$算法就是一个典型的例子。
回到这道题,应用lych的话:
假设对于i,我们求出i之前的所有向量与i的点积的和;如果所有的点积都>0 即=1,那么显然点积的和对二取模=(i-1)%2;否则如果≠(i-1)%2,显然i与i前面的某一个向量的点积=0,我们O(ND)寻找答案即可。但 是这样不一定能得到解,我们不妨随机打乱向量的顺序然后判断,这样至少是1-(1/2)^5的正确率了。
问题在3怎么做,因为不为0可能意味着为1或2,不能确定答案,但是发现在模意义下$1^2\equiv 2^2 (mod 3)$。所以只要平方一下就好了。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
using namespace std; const int N=,M=;
int n,m,mod,a[N][M],q[N],b[M],c[M][M]; bool check(int x,int y){
int tmp=;
rep(i,,m) tmp+=a[x][i]*a[y][i];
return !(tmp%mod);
} int solve(int x){
int ans=;
if (mod==)
rep(i,,m) ans^=b[i]&a[x][i],b[i]^=a[x][i];
else
rep(i,,m) rep(j,,m) ans+=c[i][j]*a[x][i]*a[x][j],c[i][j]+=a[x][i]*a[x][j];
return ans%mod;
} int main(){
freopen("meow.in","r",stdin);
freopen("meow.out","w",stdout);
scanf("%d%d%d",&n,&m,&mod);
rep(i,,n) rep(j,,m) scanf("%d",&a[i][j]),a[i][j]%=mod;
rep(i,,n) q[i]=i;
for (int T=-mod; T--; ){
if (mod==) memset(b,,sizeof(b)); else memset(c,,sizeof(c));
rep(i,,n) swap(q[i],q[rand()%(i-)+]);
rep(i,,n) if (solve(q[i])!=(i-)%mod)
rep(j,,i-) if (check(q[i],q[j])){
if (q[i]>q[j]) swap(i,j);
printf("%d %d\n",q[i],q[j]); return ;
}
}
puts("-1 -1");
return ;
}
T2:树的计数
想不到的DP题,略。
T3:小Q的修炼
这个题由于我码力极弱,玩了两个小时只写出一个暴搜拿了20+分。
#include<cstdio>
#include<algorithm>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
using namespace std; const int N=,M=;
int n,m,k,mx,tot,v[N],res[N],tmp[N];
char ch,cc,op;
struct P{ int op,a,b,c,d,u,v; }S[]; void dfs(int x,int p){
if (x>M) return;
if (p< || p>n){
if (v[]>mx){ mx=v[]; tot=x-; rep(i,,tot) res[i]=tmp[i]; }
return;
}
int T[N],T2[N];
rep(i,,m) T[i]=v[i];
while (){
if (S[p].op==){
int t=S[p].c;
if (S[p].b==) t=v[S[p].c];
if (S[p].d) t=-t;
v[S[p].a]+=t; p++;
if (p< || p>n){
if (v[]>mx){ mx=v[]; tot=x-; rep(i,,tot) res[i]=tmp[i]; }
rep(i,,m) v[i]=T[i];
return;
}
continue;
}
if (S[p].op==){
int x1,x2;
if (S[p].a==) x1=S[p].b; else x1=v[S[p].b];
if (S[p].c==) x2=S[p].d; else x2=v[S[p].d];
if (x1<x2) p=S[p].u; else p=S[p].v;
if (p< || p>n){
if (v[]>mx){ mx=v[]; tot=x-; rep(i,,tot) res[i]=tmp[i]; }
rep(i,,m) v[i]=T[i];
return;
}
continue;
}
if (S[p].op==){
rep(i,,m) T2[i]=v[i];
tmp[x]=; dfs(x+,S[p].a);
rep(i,,m) v[i]=T2[i];
tmp[x]=; dfs(x+,S[p].b);
rep(i,,m) v[i]=T[i];
return;
}
}
} int main(){
freopen("train.in","r",stdin);
freopen("train.out","w",stdout);
scanf("%d%d",&n,&m);
rep(i,,n){
scanf(" %c",&op);
if (op=='v'){
S[i].op=; scanf("%d",&S[i].a);
scanf(" %c %c",&cc,&ch);
if (ch=='c') S[i].b=; else S[i].b=;
scanf("%d",&S[i].c); if (cc=='-') S[i].d=;
}
if (op=='s'){
S[i].op=; scanf("%d%d",&S[i].a,&S[i].b);
}
if (op=='i'){
S[i].op=;
scanf(" %c",&ch);
if (ch=='c') S[i].a=; else S[i].a=;
scanf("%d",&S[i].b);
scanf(" %c",&ch);
if (ch=='c') S[i].c=; else S[i].c=;
scanf("%d",&S[i].d);
scanf("%d%d",&S[i].u,&S[i].v);
}
}
dfs(,);
rep(i,,tot) printf("%d\n",res[i]);
return ;
}
4,5,6都是DP,较复杂,略。
7,8,9,10是DP+暴力,略。
仔细观察第3个点,发现格式是每170行成为一段,段与段之间是互不影响的,所以直接段内暴搜,整体合并即可。
发现自己非常不擅长玩提答,稍微总结一下这种题的套路吧(虽然这种题没有太多套路)
1. 对码力要求较高,玩提答的时候动作一定要快,不能沉迷到游戏里去了。
2. 一般有这几种考察点:手玩,暴搜,贪心,DP,网络流,模拟退火。有些题里面会放数论算法的点。
3. 针对每个考察点需要注意的是:手玩不要搞复杂,感觉手玩比较难的时候不如考虑写暴搜。
4. 也不要一开始就急着先写暴搜,如果暴搜较复杂的话不如先看看后面的点。暴搜一般的收获是前两个点的满分和后面所有点的1~2分。
5. 一般不会有两个完全一样的点,但可能会有后面的点只是前面的代码稍作修改,或者要多跑一会而已。
6. 要多想DP和贪心,有时网络流和匈牙利也很有用。模拟退火+随机调整感觉凭自己水平还很难写出来,多写写随机化贪心。
7. 不要因为提答丢失了前面传统题的分。
Day 2
T1:矩阵游戏
最简单的一道题。首先已知f[i][1]可以通过等比数列求和公式轻松推出f[i][m]。然后合并系数可以轻松从f[1][1]得到f[n][1],最后直接从f[n][1]推到f[n][m]即可。注意公比为1要特殊处理。
关于读入,由于n和m在公比不为1时是指数,为1时是系数,所以要边读边mod p或p-1。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
using namespace std; const int mod=;
int n,m,a,b,c,d,n1,m1,X,Y;
char s[]; void Rd(int &n,int &n1){
scanf("%s",s+); int l=strlen(s+); n=; n1=;
rep(i,,l) n=(n*10ll+s[i]-'')%(mod-),n1=(n1*10ll+s[i]-'')%mod;
} int ksm(int a,int b){
int res=;
for (; b; a=1ll*a*a%mod,b>>=)
if (b&) res=1ll*res*a%mod;
return res;
} void cal1(int a,int b,int n){ if (n<) n+=mod; X=; Y=1ll*n*b%mod; }
void cal(int a,int b,int n){ if (n<) n+=mod-; X=ksm(a,n); Y=1ll*(X-)*ksm(a-,mod-)%mod*b%mod; } int main(){
freopen("matrix.in","r",stdin);
freopen("matrix.out","w",stdout);
Rd(n,n1); Rd(m,m1); scanf("%d%d%d%d",&a,&b,&c,&d);
if (a==) cal1(a,b,m1-); else cal(a,b,m-);
int p=X,q=Y,w=(p+q)%mod,u=1ll*c*p%mod,v=(1ll*c*q+d)%mod;
if (u==) cal1(u,v,n1-); else cal(u,v,n-);
w=(1ll*X+Y)%mod; w=(1ll*p*w+q)%mod; printf("%d\n",w);
return ;
}
T2:书法家
较复杂的DP,略。
T3:快餐店
首先如果是树,答案显然为直径的一半,这启发我们不要太深入的考虑环套树DP,而是使用常规的破环成树的方法。
显然所有点对间的最短路径可以都不经过某条边,枚举这条不需要的边,破环成树,在树上做前缀和与前缀最大值,再搞一搞就好了。
#include<cstdio>
#include<algorithm>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
#define For(i,x) for (int i=h[x],k; i; i=nxt[i])
typedef long long ll;
using namespace std; const int N=;
int n,cnt,tot,tim,u,v,w,dfn[N],fa[N],a[N],b[N],c[N],h[N],to[N<<],nxt[N<<],val[N<<];
ll f[N],u1[N],u2[N],v1[N],v2[N],ans;
bool d[N]; void add(int u,int v,int w){ to[++cnt]=v; nxt[cnt]=h[u]; val[cnt]=w; h[u]=cnt; } void dfs(int x){
dfn[x]=++tim;
For(i,x) if ((k=to[i])!=fa[x]){
if (!dfn[k]){ fa[k]=x; c[k]=val[i]; dfs(k); }
else if (dfn[k]>dfn[x]){
for (; k!=x; k=fa[k]) d[k]=,a[++tot]=k,b[tot]=c[k];
d[x]=; a[++tot]=x; b[tot]=val[i];
}
}
} void DP(int x,int fa){
For(i,x) if ((k=to[i])!=fa && !d[k])
DP(k,x),ans=max(ans,f[x]+f[k]+val[i]),f[x]=max(f[x],f[k]+val[i]);
} int main(){
freopen("food.in","r",stdin);
freopen("food.out","w",stdout);
scanf("%d",&n);
rep(i,,n) scanf("%d%d%d",&u,&v,&w),add(u,v,w),add(v,u,w);
dfs(); ll sm=,mx=;
rep(i,,tot) DP(a[i],);
rep(i,,tot){
sm+=b[i-]; u1[i]=max(u1[i-],f[a[i]]+sm);
v1[i]=max(v1[i-],f[a[i]]+sm+mx);
mx=max(mx,f[a[i]]-sm);
}
ll tmp=b[tot]; sm=mx=b[tot]=;
for (int i=tot; i; i--){
sm+=b[i]; u2[i]=max(u2[i+],f[a[i]]+sm);
v2[i]=max(v2[i+],f[a[i]]+sm+mx);
mx=max(mx,f[a[i]]-sm);
}
ll mn=v1[tot];
rep(i,,tot-) mn=min(mn,max(max(v1[i],v2[i+]),u1[i]+u2[i+]+tmp));
ans=max(ans,mn); printf("%lld.%d\n",ans>>,(ans&)?:);
return ;
}
NOI2013部分题解的更多相关文章
- 【fake题解】[NOI2013]向量内积
[fake题解][NOI2013]向量内积 做法1 大暴力.哪里不会T哪里. 做法2 所有数都%=k不影响结果.(废话 k的取值只有2和3,所以肯定是要分类讨论的.k=2肯定简单些啦. k=2 出现的 ...
- [bzoj3244][noi2013]树的计数 题解
UPD: 那位神牛的题解更新了,在这里. ------------------------------------------------------------------------------- ...
- 题解【bzoj3240 [NOI2013]矩阵游戏】
挖坑2333 等我把代码写完了再写
- loj#2665. 「NOI2013」树的计数
目录 题目链接 题解 代码 题目链接 loj#2665. 「NOI2013」树的计数 题解 求树高的期望 对bfs序分层 考虑同时符合dfs和bfs序的树满足什么条件 第一个点要强制分层 对于bfs序 ...
- 【BZOJ3244】【NOI2013】树的计数(神仙题)
[BZOJ3244][NOI2013]树的计数(神仙题) 题面 BZOJ 这题有点假,\(bzoj\)上如果要交的话请输出\(ans-0.001,ans,ans+0.001\) 题解 数的形态和编号没 ...
- 【BZOJ3242】【NOI2013】快餐店(动态规划)
[BZOJ3242][NOI2013]快餐店(动态规划) 题面 BZOJ 题解 假设我们要做的是一棵树,那么答案显然是树的直径的一半. 证明? 假设树的直径是\(2d\),那么此时最远点的距离是\(d ...
- 【BZOJ3243】【NOI2013】向量内积(矩阵,数论)
[BZOJ3243][NOI2013]向量内积(矩阵,数论) 题面 BZOJ 题解 这题好神仙. 首先\(60\)分直接是送的.加点随机之类的可以多得点分. 考虑正解. 我们先考虑一下暴力. 我们把\ ...
- 【BZOJ3240】【NOI2013】矩阵游戏(数论)
[BZOJ3240][NOI2013]矩阵游戏(数论) 题面 BZOJ 题解 搞什么矩阵十进制快速幂加卡常? 直接数学推导不好吗? 首先观察如何从每一行的第一个推到最后一个 \(f[i]=a·f[i- ...
- [UOJ#122][NOI2013]树的计数
[UOJ#122][NOI2013]树的计数 试题描述 我们知道一棵有根树可以进行深度优先遍历(DFS)以及广度优先遍历(BFS)来生成这棵树的 DFS 序以及 BFS 序.两棵不同的树的 DFS 序 ...
随机推荐
- BZOJ 3262: 陌上花开 CDQ
这个题大部分人用了离散然后水之,然而.....作为一只蒟蒻我并没有想到离散,而是直接拿两个区间一个对应n,一个对应k来搞,当然这两个区间是对应的,我把第一维排序,第二维CDQ,第三维树状数组,然而由于 ...
- Java并发(10)- 简单聊聊JDK中的七大阻塞队列
引言 JDK中除了上文提到的各种并发容器,还提供了丰富的阻塞队列.阻塞队列统一实现了BlockingQueue接口,BlockingQueue接口在java.util包Queue接口的基础上提供了pu ...
- bzoj2161: 布娃娃
Description 小时候的雨荨非常听话,是父母眼中的好孩子.在学校是老师的左右手,同学的好榜样.后来她成为艾利斯顿第二 代考神,这和小时候培养的良好素质是分不开的.雨荨的妈妈也为有这么一个懂事的 ...
- hdu1527取石子游戏---(威佐夫博弈)
感谢 http://www.cnblogs.com/yuyixingkong/p/3362476.html 取石子游戏 Time Limit: 2000/1000 MS (Java/Others) ...
- 01-modal
Demo示例程序源代码
源代码下载链接:01-modal.zip37.8 KB // MJAppDelegate.h // // MJAppDelegate.h // 01-modal // // Created by ...
- [bzoj3697]采药人的路径——点分治
Brief Description 采药人的药田是一个树状结构,每条路径上都种植着同种药材. 采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的. 采药人每天 ...
- bzoj 2151 贪心
几乎完全类似于1150的思路,直接参考那个就行了. http://www.cnblogs.com/BLADEVIL/p/3527193.html /************************** ...
- Linux内核同步机制之(四):spin lock【转】
转自:http://www.wowotech.net/kernel_synchronization/spinlock.html 一.前言 在linux kernel的实现中,经常会遇到这样的场景:共享 ...
- appium===安卓SDK下载很慢的解决办法
方法一:http://www.apkbus.com/forum.php?mod=viewthread&tid=240851 方法二:http://www.androiddevtools.cn/
- 输入法出现 footer被挤上去的问题
/** * 修改点击input输入框时的位置 *input框获取焦点footer隐藏,失去焦点时显示 */ $('.input-footer-none').on('focus',function(){ ...