noip模拟6(T2更新
由于蒟弱目前还没调出T1和T2,所以先写T3和T4。(T1T2更完辣! update in 6.12 07:19
T3 大佬
题目描述:
他发现katarina大佬真是太强了,于是就学习了一下katarina大佬的做题方法。
比如这是一本有n道题的练习册,katarina大佬每天都会做k道题。
第一天做第1~k题,第二天做第2 ~k+1 题……第n 天做第n-k+1 ~n 道题。
但是辣鸡 ljh 又不想太累,所以他想知道katarina大佬做完这本练习册的劳累度。
每道题有它的难度值,假设今天katarina大佬做的题目中最大难度为t,那么今天katarina大佬的劳累度就是wt?,做完这本书的劳累值就是每天的劳累值之和。
但是辣鸡ljh一道题都不会,自然也不知道题目有多难,他只知道题目的难度一定在1~m之间随机。
他想让即将参加 NOIP 的你帮他算算katarina大佬做完这本书的劳累值期望
看到是期望题,直接就跳了,回头看才知道这么水,没一会就想到正解了,奈何莫得时间了,淦。
设\(f[i]\)表示这\(k\)道题中,\(i\)是最大难度的概率。
则\(f1=(1/m)^k\),\(f2=(2/m)^k-(1/m)^k\),\(fm=1-((m-1)/m)^k\)
于是求得概率后,一天期望的贡献就是\(\sum_{i=1}^{m}w[i]*f[i]\).最后乘上总共的天数就是答案。
Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
namespace EMT
{
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;
}
#define F(i, a, b) for (register int i = a; i <= b; i++)
#define f(x) for (register int i = head[x], j; i; i = e[i].next)
#define pf printf
inline void pi(long long x)
{
pf("%lld ", x);
}
inline void pn() { printf("\n"); }
inline void ps(int a[], int size)
{
F(i, 1, size)
pi(a[i]);
pn();
}
#define int long long
const int mod=1000000007,N=510;
int ans,n,m,k;
inline int ksm(int a,int b){
int ans=1;
while(b){
if(b&1)ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}return ans;
}
int w,pre,one,now,inv;
inline signed main(){
n=read();m=read();k=read();
if(k>n){pi(0);return 0;}
F(i,1,m){
w=read();
now=ksm(i%mod,k);
one+=w*(now-pre+mod)%mod;
one%=mod;
pre=now;
}pi(one*(n-k+1)%mod*ksm(ksm(m,k),mod-2)%mod);
}
} // namespace EMT
signed main() { return EMT::main(); }
逆元最后再运算&&ksm(b&1)!!!
T4 宝藏
题目描述:
总觉得在哪里见过,原来是蓝书
但正解可忘得一干二净了,还是考场上想出的正解,结果转移时没转移全,痛失85pts
设\(f[i][s]\)表示以\(i\)为根,状态\(s\)用位运算表示已统计过的点,其中\(i\)可以用滚动数组滚掉。
用辅助数组\(len[s][k]\)表示状态为\(s\)时\(k\)距离根节点的距离,然后dp式子就显然了。
Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
namespace EMT
{
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;
}
#define F(i, a, b) for (register int i = a; i <= b; i++)
#define pf printf
inline void pi(int x)
{
pf("%d ", x);
}
inline void px(int x)
{
int ans[15]={0,0,0,0,0,0}, co = 0;
while (x)
{
ans[++co] = x & 1;
x >>= 1;
}
for (int i = 4; i >= 1; i--)
pf("%d", ans[i]);
pf(" ");
}
inline void pn() { printf("\n"); }
inline void ps(int a[], int size)
{
F(i, 1, size)
pi(a[i]);
pn();
}
const int N = 14, maxn = 50000000;
int n, m, f[1 << N], w[N][N], a[N][N], len[1 << N][N];
signed main()
{
//freopen("d.out","w",stdout);
n = read();
m = read();
F(i, 1, n)
F(j, 1, n)
if (i != j)
w[i][j] = maxn;
F(i, 1, m)
{
int x = read(), y = read();
if (x == y)
{
read();
continue;
}
if (w[x][y] != maxn)
w[y][x] = w[x][y] = min(w[x][y], read());
else
w[y][x] = w[x][y] = read(), a[x][++a[x][0]] = y, a[y][++a[y][0]] = x;
}
int ans = maxn;
F(root, 1, n)
{
F(i,1,(1<<n)-1)f[i]=maxn;
memset(len, 0, sizeof(len));
f[1 << (root - 1)] = 0;
len[1 << (root - 1)][root] = 1;
F(i, 1, (1 << n) - 1)
{
//if(root==1)px(i),pi(f[i]),pn();
if(f[i]!=maxn){
F(j, 1, n)
{
if (i & (1 << (j - 1)))
{
F(k, 1, a[j][0])
{
if (!(i & (1 << (a[j][k] - 1))))
{
if(f[i | (1 << (a[j][k] - 1))]>f[i] + w[j][a[j][k]] * len[i][j]){
F(l,1,n)len[i | (1 << (a[j][k] - 1))][l]=len[i][l];
len[i | (1 << (a[j][k] - 1))][a[j][k]] = len[i][j] + 1;
f[i | (1 << (a[j][k] - 1))] = f[i] + w[j][a[j][k]] * len[i][j];
}
}
}
}
}
}
}
ans = min(ans, f[(1 << n) - 1]);
}
pi(ans);
return 0;
}
} // namespace EMT
signed main() { return EMT::main(); }
T1 辣鸡
好具有嘲讽属性的名称。。。
题目描述:
辣鸡ljh NOI之后就退役了,然后就滚去学文化课了。
然而在上化学课的时候,数学和化学都不好的ljh却被一道简单题难住了,受到了大佬的嘲笑。
题目描述是这样的:
在一个二维平面上有一层水分子,请问形成了多少个氢键?
这个二维平面可以看做一个类似棋盘的东西,每个格子可以容纳一个水分子,左下角的格子为(0,0),这个格子右边的格子为(1,0),上方格子为(0,1),以此类推。
辣鸡ljh当然不会做了,所以他来求助JeremyGou,JeremyGou一眼就看穿了真相,并想用这道题来考一考正在做NOIP模拟赛的你。
注:在本题中,我们认为一个水分子能与和它曼哈顿距离为2且直线距离小于2的其他格子形成氢键。
简洁大法万岁!
将多个操作按x排序,\(l\),\(r\),为二者交集,\(ll\),\(rr\)为二者并集,
分情况讨论即可。
Code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
namespace EMT
{
#define int long long
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;
}
#define F(i, a, b) for (register int i = a; i <= b; i++)
#define f(x) for (register int i = head[x], j; i; i = e[i].next)
#define pf printf
inline void pi(long long x)
{
pf("%lld ", x);
}
inline void pn() { printf("\n"); }
inline void ps(bool a[], int size)
{
F(i, 1, size)
pi(a[i]);
pn();
}
const int N = 1e5 + 100;
int n, ans, maxl, maxh;
int maxx, maxy;
struct ques
{
int x1, y1, x2, y2;
}q[N];
inline bool com(ques a, ques b)
{
if (a.x1 == b.x1)return a.x2 < b.x2;
else return a.x1<b.x1;
}
inline int size(int x,int y,int X,int Y){
return (Y-y)*(X-x)*2;
}
inline void s(){pf("shit\n");}
inline void getans(int a,int b){
int lx1=q[a].x1,rx1=q[a].x2,ly1=q[a].y1,ry1=q[a].y2;
int lx2=q[b].x1,rx2=q[b].x2,ly2=q[b].y1,ry2=q[b].y2;
if(ry1+1==ly2||ry2+1==ly1)
{
int l=max(lx1,lx2),ll=min(lx1,lx2);
int rr=max(rx1,rx2),r=min(rx1,rx2);
if(l>r+1)return;
if(l==r+1){ans++;return;}
if(l<=r)ans+=2*(r-l);
if(l>ll)ans++;if(r<rr)ans++;
}
if(rx1+1==lx2)
{
int l=max(ly1,ly2),ll=min(ly1,ly2);
int r=min(ry1,ry2),rr=max(ry1,ry2);
if(l>r+1)return;
if(l==r+1){ans++;return;}
if(l<=r)ans+=2*(r-l);
if(l>ll)ans++;if(r<rr)ans++;
}
}
signed main()
{
n = read();
F(i, 1, n)q[i].x1=read()+1,q[i].y1=read()+1,q[i].x2=read()+1,q[i].y2=read()+1;
F(i,1,n)ans+=size(q[i].x1,q[i].y1,q[i].x2,q[i].y2);
sort(q+1,q+n+1,com);
//pi(ans);s();s();pn();
F(i,1,n)F(j,i+1,n)if(q[j].x1-q[i].x2>1)break;else getans(i,j);
pi(ans);
return 0;
}
} // namespace EMT
signed main() { return EMT::main(); }
/*
10
0 10 0 10
0 8 0 9
0 0 7 0
0 2 9 2
0 3 10 7
1 8 8 9
4 10 8 10
8 0 9 1
9 8 10 8
10 0 10 2
*/
T2 模板
题目描述:
辣鸡ljh NOI之后就退役了,然后就滚去学文化课了。
他每天都被katarina大神虐,仗着自己学过一些姿势就给katarina大神出了一道题。
有一棵 \(n\) 个节点的以 1 号节点为根的树,每个节点上有一个小桶,节点\(u\)上的小桶可以容纳\(k_{u}\)个小球,ljh每次可以给一个节点到根路径上的所有节点的小桶内放一个小球,如果这个节点的小桶满了则不能放进这个节点,在放完所有小球之后就企图去***难katarina大神,让katarina大神回答每个节点的小桶内的小球有多少种颜色。
然而katarina大神一眼就秒掉了,还说这就是一道傻逼模板题。
现在katarina大神想考考即将参加NOIP2019的你能不能回答上辣鸡ljh的问题。
第一行,一个整数n,树上节点的数量。
接下来n ? 1行,每行两个整数u, v,表示在u, v之间有一条边。
接下来一行n个整数, ~ 表示每个节点上的小桶数量。
下一行是一个整数m,表示ljh进行的操作数量。
接下来m行,每行两个整数x, c,分别表示进行操作的节点和小球颜色。
下一行是一个整数Q,表示你需要回答的询问数。
接下来Q行,每行一个整数x,表示一个询问。
本来昨天就能A掉的,结果没考虑到负数的情况,快读直接跳过负号,
导致连WA n次的惨烈局面。(话说要是我不看测试点还要调多久啊。。。
教训:以后打快读不能偷懒为了卡一点小常数忽略负号了。
本题让我对\(splay\)的认识加深了许多。
首先是以修改时间为下标,修改时记录上每个点的时间,查询时查询时间区间就行了。
另外,对于每个点一开始都建一个\(splay\),其中包含\(root\)和一个\(map\)记录是否出现过这种小球。
当修改时先只修改最子叶的\(splay\),因为下面有着\(dfs\),可以将子树的状态合并到父节点上
至于合并的方法,是启发式合并,以前一直以为这是个什么特别厉害的东西,其实就是暴力把所有子树上的节点按照传统方式插入到父节点上...(父节点:size较大的点;
子结点:size小,插入简便的点——和\(splay\)上的父节点、子结点区分开来,这么说来,其实线段树也可以这么做吧
于是我们就可以在\(dfs\)的时候预处理出每个结点的答案,查询时直接输出即可。
\(splay\)和\(map\)的结合应用\(get\sqrt{}\)
还有,对于每个结点有一个\(rec\)数组,相当于记录了该节点在哪一颗\(splay\)树上,
在合并时如果合并到子树上就更改父亲的\(rec\),而合并到父亲上就不用更改了,因为子树的答案已经统计完了,修改\(rec\)只会浪费一点时间。
\(splay\)的中序遍历\(get\sqrt{}\)(因为左子树时间小,右子树时间大,父节点时间位于二者之间,所以按照左—父—右的顺序插入。
到这里蒟弱的思路就发表完毕了,下面是code:
Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
namespace EMT
{
#define F(i,a,b) for(register int i=a;i<=b;i++)
const int N=1e5+100;
inline 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;}
struct node{
int son[2],tim,size,cnt,val,fa,col;
}t[N<<2];
int head[N],co,num,ans1,rec[N],n,m,q,now;
struct edge{int next,to;}e[N<<1];
inline void add(int next,int to){e[++co].next=head[next],e[co].to=to,head[next]=co;}
struct tree{
map<int,int>mp;
int root;
inline int siz(){return t[root].size;}
inline int get(int x){return t[t[x].fa].son[1]==x;}
inline void up(int x){t[x].size=t[t[x].son[1]].size+t[t[x].son[0]].size+1;t[x].cnt=t[t[x].son[1]].cnt+t[t[x].son[0]].cnt+t[x].val;}
inline void res(int x){
int old=t[x].fa,oldf=t[old].fa,k=get(x);
t[old].son[k]=t[x].son[k^1];
t[t[x].son[k^1]].fa=old;
t[x].son[k^1]=old;t[old].fa=x;
if(oldf)t[oldf].son[t[oldf].son[1]==old]=x;
t[x].fa=oldf;
up(old);up(x);
}
inline void splay(int x){
for(register int fa;(fa=t[x].fa);res(x))
if(t[fa].fa)res(get(fa)==get(x)?fa:x);
root=x;
}
inline void insert(int tim,int col,int val){
int f=0,x=root;bool bg;
while((!bg)||(x&&t[x].tim!=tim))bg=1,f=x,x=t[x].son[tim>t[x].tim];
x=++num;
if(f)t[f].son[tim>t[f].tim]=x;
t[x].tim=tim;t[x].val=t[x].cnt=val;t[x].col=col;t[x].fa=f;t[x].size=1;
splay(x);
}
inline void change(int tim){
int x=root;
while(x&&t[x].tim!=tim)x=t[x].son[tim>t[x].tim];
if(x)t[x].val=0;splay(x);
}
inline int find(int tim,int col){
if(!mp[col]){
mp[col]=tim;
return 1;
}
else if(mp[col]>tim){
change(mp[col]);
mp[col]=tim;
return 1;
}
else return 0;
}
inline int findx(int x,int lim){
if(!x)return 0;
if(t[t[x].son[0]].size>=lim)findx(t[x].son[0],lim);
else if(t[t[x].son[0]].size+1>=lim)return t[t[x].son[0]].cnt+t[x].val+ans1;
else ans1+=t[t[x].son[0]].cnt+t[x].val,findx(t[x].son[1],lim-t[t[x].son[0]].size-1);
}
inline int findval(int lim){
ans1=0;
if(!lim)return 0;
if(lim>=t[root].size)return t[root].cnt;
return findx(root,lim);
}
}a[N];
inline void make(int x){
if(!x)return;
make(t[x].son[0]);
a[now].insert(t[x].tim,t[x].col,a[now].find(t[x].tim,t[x].col));
make(t[x].son[1]);
}int ans[N],k[N];
inline void dfs(int x,int fa){
for(register int i=head[x],j;i;i=e[i].next){
j=e[i].to;if(j==fa)continue;
dfs(j,x);
if(a[rec[x]].siz()<a[rec[j]].siz()){
now=rec[j];
make(a[rec[x]].root);
rec[x]=now;
}
else{
now=rec[x];
make(a[rec[j]].root);
}
}
ans[x]=a[rec[x]].findval(k[x]);
}
inline short main(){
freopen("ac7.in","r",stdin);
freopen("my.out","w",stdout);
n=read();
F(i,1,n-1){
int x=read(),y=read();add(x,y);add(y,x);
}
F(i,1,n)k[i]=read(),rec[i]=i;
m=read();
F(i,1,m){
int x=read(),y=read();
a[rec[x]].insert(i,y,a[rec[x]].find(i,y));
}
dfs(1,0);
q=read();
while(q--){
int x=read();
printf("%d\n",ans[x]);
}
return 0;
}
}
signed main() { return EMT::main();}