noi.ac上的一套(假)NOI题

本来想着可以刷点通过量的,结果发现好像并不是这样的。

整数

description

给你\(n,p\),要你求\(\sum_{k=1}^n\sum_{i=1}^k\sum_{j=1}^k\gcd(i,j,k) \mod p\)。

\(n\le3\times10^8\)

sol

\[\sum_{k=1}^n\sum_{i=1}^k\sum_{j=1}^k\gcd(i,j,k)=\sum_{d=1}^nd\sum_{k=1}^n\sum_{i=1}^k\sum_{j=1}^k[\gcd(i,j,k)=d]\\=\sum_{d=1}^nd\sum_{k=1}^{n/d}\sum_{i=1}^k\sum_{j=1}^k[\gcd(i,j,k)=1]\\=\sum_{d=1}^nd\sum_{i=1}^n\mu(i)\sum_{j=1}^{n/id}j^2\\=\sum_{d=1}^nd\sum_{i=1}^n\mu(i)\frac{\lfloor\frac n{id}\rfloor(\lfloor\frac n{id}\rfloor+1)(2\lfloor\frac n{id}\rfloor+1)}{6}\\=\sum_{T=1}^n\frac{\lfloor\frac nT\rfloor(\lfloor\frac nT\rfloor+1)(2\lfloor\frac nT\rfloor+1)}{6}\sum_{d|T}d\mu(\frac Td)\\=\sum_{T=1}^n\frac{\lfloor\frac nT\rfloor(\lfloor\frac nT\rfloor+1)(2\lfloor\frac nT\rfloor+1)}{6}\varphi(T)\]

前半部分数论分块,后半部分用杜教求\(\varphi(n)\)的前缀和。

code

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1e6+5;
int n,mod,inv,zhi[N],pri[N],tot,phi[N],Phi[N],ans;
int fastpow(int a,int b){
    int res=1;
    while (b) {if (b&1) res=1ll*res*a%mod;a=1ll*a*a%mod;b>>=1;}
    return res;
}
int S(int x){
    return 1ll*x*(x+1)%mod*(x+x+1)%mod*inv%mod;
}
int P(int x){
    if (x<N) return phi[x];
    if (~Phi[n/x]) return Phi[n/x];
    int res=0;
    for (int i=2,j;i<=x;i=j+1){
        j=x/(x/i);
        res=(res+1ll*(j-i+1)*P(x/i))%mod;
    }
    res=((1ll*x*(x+1)>>1)-res+mod)%mod;
    return Phi[n/x]=res;
}
int main(){
    scanf("%d%d",&n,&mod);inv=fastpow(6,mod-2);
    phi[1]=1;
    for (int i=2;i<N;++i){
        if (!zhi[i]) pri[++tot]=i,phi[i]=i-1;
        for (int j=1;i*pri[j]<N;++j){
            zhi[i*pri[j]]=1;
            if (i%pri[j]) phi[i*pri[j]]=phi[i]*(pri[j]-1);
            else {phi[i*pri[j]]=phi[i]*pri[j];break;}
        }
    }
    for (int i=1;i<N;++i) phi[i]=(phi[i]+phi[i-1])%mod;
    memset(Phi,-1,sizeof(Phi));
    for (int i=1,j;i<=n;i=j+1){
        j=n/(n/i);
        ans=(ans+1ll*(P(j)-P(i-1)+mod)*S(n/i))%mod;
    }
    printf("%d\n",ans);return 0;
}

蚯蚓排队

description

有一棵\(n\)个点的树和\(m\)只蚯蚓,你需要给条蚯蚓在树上找一个节点住下来,存在\(q\)条限制,每条形如蚯蚓\(a\)跟蚯蚓\(b\)在树上居住的节点间的简单路径经过点\(c\)。求一组合法解。

\(n,m\le250,q\le5\times10^4\)

sol

\(\mbox{2-sat}\)。是HiddenRabbits这个题的弱化版。

建立\(2nm\)个变量表示第\(i\)只蚯蚓在/不在\(j\)的子树中。需要预处理一些连边。对于每条限制,可以O(度数)​地连边。总边数大概是\(O(mn^2+qn)\)级别的。

code

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int gi(){
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-') w=0,ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return w?x:-x;
}
const int N = 2e5+5;
const int M = 3e7+5;
int n,m,q,TO[N],NXT[N],HD[N],tot,fa[N],dep[N],st[N],ed[N];
int S[255][255],to[M],nxt[M],head[N],cnt,dfn[N],low[N],tim,vis[N],s[N],bel[N],scc;
void dfs(int u,int f){
    fa[u]=f;dep[u]=dep[f]+1;st[u]=++tim;
    for (int e=HD[u];e;e=NXT[e])
        if (TO[e]!=f) dfs(TO[e],u);
    ed[u]=tim;
}
bool in(int u,int v){return st[u]>=st[v]&&st[u]<=ed[v];}
void link(int u,int v){
    to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;
    u^=1;v^=1;swap(u,v);
    to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;
}
void Tarjan(int u){
    dfn[u]=low[u]=++tim;vis[s[++s[0]]=u]=1;
    for (int e=head[u];e;e=nxt[e])
        if (!dfn[to[e]]) Tarjan(to[e]),low[u]=min(low[u],low[to[e]]);
        else if (vis[to[e]]) low[u]=min(low[u],dfn[to[e]]);
    if (dfn[u]==low[u]){
        ++scc;int x;
        do x=s[s[0]--],bel[x]=scc,vis[x]=0;while (x^u);
    }
}
int main(){
    n=gi();m=gi();q=gi();
    for (int i=1;i<n;++i){
        int u=gi(),v=gi();
        TO[++tot]=v;NXT[tot]=HD[u];HD[u]=tot;
        TO[++tot]=u;NXT[tot]=HD[v];HD[v]=tot;
    }
    dfs(1,0);tot=-1;
    for (int i=1;i<=m;++i)
        for (int j=1;j<=n;++j)
            S[i][j]=++tot,++tot;
    for (int i=1;i<=m;++i){
        link(S[i][1]^1,S[i][1]);
        for (int j=2;j<=n;++j)
            link(S[i][j],S[i][fa[j]]);
        for (int j=2;j<=n;++j)
            for (int k=j+1;k<=n;++k)
                if (!in(j,k)&&!in(k,j)) link(S[i][j],S[i][k]^1);
    }
    while (q--){
        int a=gi(),b=gi(),c=gi();
        for (int e=HD[c];e;e=NXT[e])
            if (TO[e]!=fa[c])
                link(S[a][TO[e]],S[b][TO[e]]^1);
        if (c>1) link(S[a][c]^1,S[b][c]);
    }
    for (int i=tim=0;i<=tot;++i) if (!dfn[i]) Tarjan(i);
    for (int i=1;i<=m;++i){
        int res=0;
        for (int j=1;j<=n;++j)
            if (bel[S[i][j]]<bel[S[i][j]^1]) res=dep[j]>dep[res]?j:res;
        printf("%d ",res);
    }
    return puts(""),0;
}

泳池

description

有一个\(n\times m\)的矩形,每个地方可以填一个非负整数。要求使得第\(i\)行的最大值为\(a_i\),第\(i\)列的最大值为\(b_i\)。求方案数模\(10^9+9\)。

\(n,m\le200\)

sol

可以先考虑一个子问题:有一个\(n\times m\)的矩形,每个地方可以填\([0,h]\)中的一个数,要求每行每列的最大值都恰好是\(h\)。求方案数。

考虑容斥。枚举\(i\)行\(j\)列强制没有达到最大值,则有

\[Ans=\sum_{i=0}^n\sum_{j=0}^m(-1)^{i+j}\binom ni\binom mjh^{ij}(h+1)^{nm-ij}\]

回到原题。把最大值相同的那些行与列放在一起考虑,可以得到一个类似上式的结论。

code

#include<cstdio>
#include<algorithm>
using namespace std;
int gi(){
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-') w=0,ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return w?x:-x;
}
const int N = 205;
const int mod = 1e9+9;
int n,m,C[N][N],a[N],b[N],Ans=1;
int fastpow(int a,int b){
    int res=1;
    while (b) {if (b&1) res=1ll*res*a%mod;a=1ll*a*a%mod;b>>=1;}
    return res;
}
bool cmp(int i,int j){return i>j;}
int main(){
    n=gi();m=gi();
    for (int i=C[0][0]=1;i<N;++i)
        for (int j=C[i][0]=1;j<=i;++j)
            C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
    for (int i=1;i<=n;++i) a[i]=gi();sort(a+1,a+n+1,cmp);
    for (int i=1;i<=m;++i) b[i]=gi();sort(b+1,b+m+1,cmp);
    a[n+1]=b[m+1]=-1;
    for (int x=0,y=0;x<n||y<m;){
        int h=max(a[x+1],b[y+1]),xx=x,yy=y,ans=0;
        while (a[x+1]==h) ++x;while (b[y+1]==h) ++y;
        for (int i=0;i<=x-xx;++i)
            for (int j=0;j<=y-yy;++j){
                int S1=(x-i)*(y-j)-xx*yy,S2=x*y-S1-xx*yy;
                int res=1ll*C[x-xx][i]*C[y-yy][j]%mod*fastpow(h+1,S1)%mod*fastpow(h,S2)%mod;
                if ((i+j)&1) ans=(ans-res+mod)%mod;
                else ans=(ans+res)%mod;
            }
        Ans=1ll*Ans*ans%mod;
    }
    printf("%d\n",Ans);return 0;
}

游戏

description

给你一个数列\(\{a_i\}\),每次选出两个不相交的区间\([l_1,r_1],[l_2,r_2]\),要求\(r_1<l_2\),此时获得的收益是两个区间的区间最小值的最小值。求所有不同的选法的收益之和模\(10^9+7\) 。

\(n\le2\times10^5\)

sol

可以视作不存在原序列中相同的值,若存在则按下标为第二关键字排序即可。

考虑枚举一个位置\(p\),计算其作为最小值的方案数。

找到\(p\)左右两边第一个小于\(p\)的位置\(l,r\),那么两个区间的选取就有三种方式:

1、\(l_1\in[l,p],r_1\in[p,r],l_2,r_2\in[p+1,r]\);

2、\(r_2\in[p,r],l_2\in[l,p],l_1,r_1\in[l,p-1]\);

3、一个区间的左端点\(\in[l,p]\)右端点\(\in[p,r]\),另一个区间不包含于\([l,r]\),且最小值不大于\(a_p\)。

前两种好算,最后一种在计算时需要维护“另一个区间”的个数。按照权值从小到大处理即可。

复杂度\(O(n\log n)\)。

code

#include<cstdio>
#include<algorithm>
using namespace std;
int gi(){
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-') w=0,ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return w?x:-x;
}
const int N = 2e5+5;
const int mod = 1e9+7;
int n,a[N],b[N],S[N],top,L[N],R[N],sum[N],num,ans;
bool cmp(int i,int j){return a[i]==a[j]?i<j:a[i]<a[j];}
int main(){
    n=gi();num=(1ll*n*(n+1)>>1)%mod;
    for (int i=1;i<=n;++i) a[i]=gi(),b[i]=i;
    sort(b+1,b+n+1,cmp);
    for (int i=1;i<=n;++i){
        while (top&&a[S[top]]>a[i]) --top;
        L[i]=S[top]+1;S[++top]=i;
    }
    S[top=0]=n+1;
    for (int i=n;i;--i){
        while (top&&a[S[top]]>=a[i]) --top;
        R[i]=S[top]-1;S[++top]=i;
    }
    for (int i=1;i<=n;++i) sum[i]=(sum[i-1]+(1ll*i*(i+1)>>1))%mod;
    for (int i=1;i<=n;++i){
        int p=b[i],l=L[p],r=R[p],res=(1ll*(r-l+1)*(r-l+2)>>1)%mod;
        res=1ll*(p-l+1)*(r-p+1)%mod*(num-res+mod)%mod;
        res=(res+1ll*(p-l+1)*sum[r-p])%mod;
        res=(res+1ll*(r-p+1)*sum[p-l])%mod;
        ans=(ans+1ll*res*a[p])%mod;
        num=(num-1ll*(p-l+1)*(r-p+1)%mod+mod)%mod;
    }
    printf("%d\n",ans);return 0;
}

咕咕咕?

noi.ac上的一套(假)NOI题的更多相关文章

  1. # NOI.AC省选赛 第五场T1 子集,与&最大值

    NOI.AC省选赛 第五场T1 A. Mas的童年 题目链接 http://noi.ac/problem/309 思路 0x00 \(n^2\)的暴力挺简单的. ans=max(ans,xor[j-1 ...

  2. NOI.AC NOIP模拟赛 第六场 游记

    NOI.AC NOIP模拟赛 第六场 游记 queen 题目大意: 在一个\(n\times n(n\le10^5)\)的棋盘上,放有\(m(m\le10^5)\)个皇后,其中每一个皇后都可以向上.下 ...

  3. NOI.AC NOIP模拟赛 第三场 补记

    NOI.AC NOIP模拟赛 第三场 补记 列队 题目大意: 给定一个\(n\times m(n,m\le1000)\)的矩阵,每个格子上有一个数\(w_{i,j}\).保证\(w_{i,j}\)互不 ...

  4. NOI.AC 32 Sort——分治

    题目:http://noi.ac/problem/32 从全是0和1的情况入手,可以像线段树一样分治下去,回到本层的时候就是左半部的右边是1,右半部的左边是0,把这两部分换一下就行.代价和时间一样是n ...

  5. NOI.AC 31 MST——整数划分相关的图论(生成树、哈希)

    题目:http://noi.ac/problem/31 模拟 kruscal 的建最小生成树的过程,我们应该把树边一条一条加进去:在加下一条之前先把权值在这一条到下一条的之间的那些边都连上.连的时候要 ...

  6. NOI.AC #31 MST —— Kruskal+点集DP

    题目:http://noi.ac/problem/31 好题啊! 题意很明白,对于有关最小生成树(MST)的题,一般是要模拟 Kruskal 过程了: 模拟 Kruskal,也就是把给出的 n-1 条 ...

  7. [NOI.AC 2018NOIP模拟赛 第三场 ] 染色 解题报告 (DP)

    题目链接:http://noi.ac/contest/12/problem/37 题目: 小W收到了一张纸带,纸带上有 n个位置.现在他想把这个纸带染色,他一共有 m 种颜色,每个位置都可以染任意颜色 ...

  8. NOI.AC#2139-选择【斜率优化dp,树状数组】

    正题 题目链接:http://noi.ac/problem/2139 题目大意 给出\(n\)个数字的序列\(a_i\).然后选出一个不降子序列最大化子序列的\(a_i\)和减去没有任何一个数被选中的 ...

  9. NOI.AC#2144-子串【SAM,倍增】

    正题 题目链接:http://noi.ac/problem/2144 题目大意 给出一个字符串\(s\)和一个序列\(a\).将字符串\(s\)的所有本质不同子串降序排序后,求有多少个区间\([l,r ...

随机推荐

  1. HIVE: 自定义TextInputFormat (旧版MapReduceAPI ok, 新版MapReduceAPI实现有BUG?)

    我们的输入文件 hello0, 内容如下: xiaowang 28 shanghai@_@zhangsan 38 beijing@_@someone 100 unknown 逻辑上有3条记录, 它们以 ...

  2. flask jinja的宏

    form中关于表单的定义 class AreaListForm(Form): area1 = BooleanField(u'1区', default=False) area2 = BooleanFie ...

  3. 怎么测试一个web登录页面

    在以前的面试和同事面试交流的过程中,有多次被问到:“给你一个登录页面,上面有2个textbox,一个提交按钮,你将怎么测试”?或问,请针对这个页面设计30个以上的test case. 此题的考察目的: ...

  4. 通过自动回复机器人学Mybatis:MySQL脚本 + db >> dao >> service >> servlet

    留着参考 makeData.sql delimiter // create procedure make_data() begin declare i int ; do insert into mes ...

  5. Installing VirtualBox DKMS in Kali 2.0

    Kali linux is one of the mainly used operating system by the Ethical hackers and information securit ...

  6. 从头到尾测地理解KMP算法【转】

    本文转载自:http://blog.csdn.net/v_july_v/article/details/7041827 1. 引言 本KMP原文最初写于2年多前的2011年12月,因当时初次接触KMP ...

  7. java虚拟机类加载

    java虚拟机中类的加载 (JVM的大致结构图) 从发class文件到内存中的类,按先后顺序,需要经过加载,链接以及初始化三大步骤. java语言的类型可分为两大类:基本类型(primitive ty ...

  8. hbase(三)coprocessor

    介绍 coprocessor这个单词看起来很神秘,直译为协处理器,其实可以理解成依赖于regionserver进程的辅助处理接口. hbae在0.92版本之后提供了coprocessor接口.目前hb ...

  9. Spring Cloud 开发的一些推荐规划

    1.提供一个统一的 父 pom 依赖    作用:统一版本与引入必要依赖 2.提供一个模板模型. 作用: 开发人员不必关系具体基础启动项 3.提供一个统一基础配置模型 作用: 开发人员不比太过关注与必 ...

  10. [转]Python的getattr(),setattr(),delattr(),hasattr()

    getattr()函数是Python自省的核心函数,具体使用大体如下: 获取对象引用getattrGetattr用于返回一个对象属性,或者方法 class A: def __init__(self): ...