2017-3-3校内训练

hzwer出丧题虐人啦 ACM赛制 4/7

A.恼人的青蛙

题目大意:给定N*M矩阵上K个点,定义一条合法路径为从矩形外一点沿一条直线穿过矩形,每次走相同长度且在矩形内每步都要踩在给定点上,问经过给定点最多的路径经过几个点(若小于3输出0)(N,M,K<=5000)。

思路:把点按横坐标第一关键字纵坐标第二关键字排序,f[i][j]表示有一条到i的路径,i上一个点是j,此时路径经过点数,每次确定i,j后就可以根据i,j算出j再前一个点的坐标,直接转移,复杂度O(K^2)。评测机极慢稍微卡卡常才能过。

#include<cstdio>
#include<algorithm>
using namespace std;
#define MN 5000
struct P{int x,y;}p[MN+5];
bool cmp(P a,P b){return a.x==b.x?a.y<b.y:a.x<b.x;}
short g[MN+5][MN+5],f[MN+5][MN+5];
int n,m,k,i,j,x,y,ans=0;
inline int G(int x,int y){return x>0&&x<=n&&y>0&&y<=m?g[x][y]:-1;}
inline int cal(int a,int b){return (a<<1)-b;}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for(i=1;i<=k;++i)scanf("%d%d",&p[i].x,&p[i].y);
    sort(p+1,p+k+1,cmp);
    for(i=1;i<=k;++i)
    {
        g[p[i].x][p[i].y]=i;
        for(j=1;j<i;++j)
        {
            x=G(cal(p[j].x,p[i].x),cal(p[j].y,p[i].y));
            f[i][j]=x?x<0?2:f[j][x]+1:-k;
            if(G(cal(p[i].x,p[j].x),cal(p[i].y,p[j].y))<0&&f[i][j]>ans)ans=f[i][j];
        }
    }
    printf("%d",ans<3?0:ans);
}

C.本原串

题目大意:求所有长度为N的01串中有多少个不存在小于N的循环节(循环节长度应能整除N),答案对2008取模(N<=100,000,000)。

思路:长度为N的01串有2^N个,考虑去掉有循环节的,先O(N^0.5)求出N的所有因数,排序,对所有小于N的因数记si=-1表示以该因数为循环节的01串个数对答案贡献的倍数。从大往小计算,遇到第i个因数ai,答案加上si*2^ai,由于可能被重复统计,对每个i再向前找到第j个因数满足j<i且aj整除ai,sj-=si,ai的所有因数必然都被n的所有因数包含,这样即可不重不漏的统计。复杂度不好计算,总之很靠谱,O(能过)。

#include<cstdio>
#include<algorithm>
using namespace std;
#define MOD 2008
int pw(int y)
{
    int r=1,t=2;
    for(;y;y>>=1,t=t*t%MOD)if(y&1)r=r*t%MOD;
    return r;
}
#define MN 20000
int n,z[MN+5],zn,s[MN+5];
int main()
{
    int i,j,ans;
    while(~scanf("%d",&n))
    {
        for(zn=0,i=1;i*i<n;++i)if(n%i==0)z[++zn]=i,z[++zn]=n/i;
        if(i*i==n)z[++zn]=i;
        sort(z+1,z+zn+1);
        for(ans=pw(n),i=1;i<zn;++i)s[i]=-1;
        for(i=zn;--i;)
        {
            ans=(ans+s[i]*pw(z[i]))%MOD;
            for(j=i;--j;)if(z[i]%z[j]==0)s[j]=(s[j]-s[i])%MOD;
        }
        printf("%d\n",(ans+MOD)%MOD);
    }
}

D.Optimal Milking

题目大意:K台机器,C头奶牛,每头奶牛对应一台机器,每台机器对应不超过M头奶牛,给出K+C个点的图,每个点表示一头奶牛或一台机器,要求最小化奶牛机器成功配对后奶牛到其配对机器路径长度的最大值,求出这个值。(K<=30,C<=200,M<=15)

思路:二分答案,网络流check。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read()
{
    int x;char c;
    while((c=getchar())<‘0‘||c>‘9‘);
    for(x=c-‘0‘;(c=getchar())>=‘0‘&&c<=‘9‘;)x=(x<<3)+(x<<1)+c-‘0‘;
    return x;
}
#define MN 230
#define ME 6230
#define S MN+1
#define T MN+2
#define INF 0x3FFFFFFF
struct edge{int nx,t,w;}e[ME*2+5];
int h[MN+5],en,n,m,w,g[MN+5][MN+5];
inline void ins(int x,int y,int w)
{
    e[++en]=(edge){h[x],y,w};h[x]=en;
    e[++en]=(edge){h[y],x,0};h[y]=en;
}
int d[MN+5],q[MN+5],qn,c[MN+5];
bool bfs()
{
    int i,j;
    memset(d,0,sizeof(d));
    for(d[q[i=qn=0]=S]=1;i<=qn;++i)for(j=c[q[i]]=h[q[i]];j;j=e[j].nx)
        if(e[j].w&&!d[e[j].t])d[q[++qn]=e[j].t]=d[q[i]]+1;
    return d[T];
}
int dfs(int x,int r)
{
    if(x==T)return r;
    int u=0,k;
    for(int&i=c[x];i;i=e[i].nx)if(e[i].w&&d[x]+1==d[e[i].t])
    {
        k=dfs(e[i].t,r-u<e[i].w?r-u:e[i].w);
        u+=k;e[i].w-=k;e[i^1].w+=k;
        if(u==r)return u;
    }
    return d[x]=0,u;
}
bool check(int x)
{
    int i,j,ans=0;
    memset(h,0,sizeof(h));en=1;
    for(i=1;i<=n;++i)ins(S,i,w);
    for(i=1;i<=m;++i)ins(i+n,T,1);
    for(i=1;i<=n;++i)for(j=1;j<=m;++j)
        if(g[i][j+n]<=x)ins(i,j+n,1);
    while(bfs())ans+=dfs(S,INF);
    return ans==m;
}
int main()
{
    int i,j,k,l,r,mid,ans;
    n=read();m=read();w=read();
    for(i=1;i<=n+m;++i)for(j=1;j<=n+m;++j)
    {
        g[i][j]=read();
        if(i!=j&&!g[i][j])g[i][j]=INF;
    }
    for(k=1;k<=n+m;++k)for(i=1;i<=n+m;++i)for(j=1;j<=n+m;++j)
        g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
    for(l=0,r=INF;l<=r;)
        if(check(mid=l+r>>1))ans=mid,r=mid-1;
        else l=mid+1;
    printf("%d",ans);
}

E.King‘s Rout

题目大意:1~N的数,M条限制关系,每条要求一个数必须在另一个的前面,求一个方案使得满足所有限制条件且1在最前面,1位置相同的情况下2在最前面,以此类推。(N<=200,000,M<=400,000)。

思路:拓扑排序,可以发现反过来字典序最大即为题目中要求的方案,用堆维护即可。

#include<cstdio>
#include<queue>
using namespace std;
inline int read()
{
    int x=0;char c;
    while((c=getchar())<‘0‘||c>‘9‘);
    for(;c>=‘0‘&&c<=‘9‘;c=getchar())x=(x<<3)+(x<<1)+c-‘0‘;
    return x;
}
#define MN 200000
#define MM 400000
priority_queue<int> pq;
struct edge{int nx,t;}e[MM+5];
int h[MN+5],en,r[MN+5],ans[MN+5];
inline void ins(int x,int y){e[++en]=(edge){h[x],y};h[x]=en;}
int main()
{
    int n,m,i,j;
    n=read();m=read();
    while(m--)++r[i=read()],ins(read(),i);
    for(i=1;i<=n;++i)if(!r[i])pq.push(i);
    for(i=n;i;--i)
    {
        ans[i]=pq.top();pq.pop();
        for(j=h[ans[i]];j;j=e[j].nx)if(!--r[e[j].t])pq.push(e[j].t);
    }
    for(i=1;i<=n;++i)printf("%d ",ans[i]);
}
时间: 2024-10-14 23:35:14

2017-3-3校内训练的相关文章

2017.09.03校内训练

T1:卡片 题解:这很明显,是一道选择题!!! 我们考虑每一种情况:只有一种卡片时,很显然最后剩下的只能是这一种:有三种卡片时,可以变成各只有一张,无论选取哪两张,都可以变成剩下的那一张,因此每一种都可以剩下:有两种的情况:若这两种都有两张以上,便可以各取一张合成没有的那一种,最后结果请参见上一条:若有一种只有一张,另一种有多张,则每一次的转化操作都要使用到较多的那种一张,不论如何都不可能合成较多张的那一种.因此结果是除了多于一张的那一种以外的其它两种:若这两种各只有一张,则结果必定是没有的那一

2017.09.24校内训练

T1:个人卫生综合征 题目描述: 每天BBS都要从家里经过城市中的一段路到学校刷五三.城市中一共有n个路口和m条双向道路,每条双向道路都连接着两个路口ai.bi且有一定的时间花费vi.BBS家编号为1,学校编号为n.今天,BBS由于个人卫生综合征导致他很迟才离开家,他想用膜法改变k条道路的长度使通过其的时间花费vi变为0.现在他问你改变道路长度之后他到学校的最小时间花费是多少? 输入格式: 第一行为三个整数n.m.k,接下来的m行每行三个整数ai,bi,vi,分别表示这条路连着的两个路口和通过其

2017.6.11 校内模拟赛

题面及数据及std(有本人的也有原来的) :2017.6.11 校内模拟赛 T1 自己在纸上模拟一下后就会发现 可以用栈来搞一搞事情 受了上次zsq 讲的双栈排序的启发.. 具体就是将原盘子大小copy一下排个序 用两个指针维护两个数组(原数据 和 排序后的数据), 即分为1数据和2数组 将小于1指针指向的数据的2数组中的数据全部压入栈中 后进行消除, 将栈栈顶元素与当前1数组中的1指针指向的元素进行比较 相同则消除 后重复过程 直至指针超过N 后判断一下是否两个指针都超过了N... #incl

「csp校内训练 2019-10-24」解题报告

「csp校内训练 2019-10-24」解题报告 T1.猴猴吃苹果 \(Description\) 猴猴最喜欢在树上玩耍,一天猴猴又跳上了一棵树,这棵树有 \(N \ (N \leq 50000)\) 个苹果,每个苹果有一个编号,分别为 \(0\) ~ \(N - 1\) 它们之间由 \(N-1\) 个树枝相连,猴猴可以从树枝的一端爬到树枝的另一端,所以猴猴可以从任意一个苹果的位置出发爬到任意猴猴想去的苹果的位置. 猴猴开始在编号为 \(K \ (K < N)\) 的苹果的位置,并且把这个苹果吃

「csp校内训练 2019-10-30」解题报告

「csp校内训练 2019-10-30」解题报告 T1.树 题目链接(逃) \(Description\): 现在有一棵树,共 \(N\) 个节点. 规定:根节点为 \(1\) 号节点,且每个节点有一个点权. 现在,有 \(M\) 个操作需要在树上完成,每次操作为下列三种之一: \(1 \ x \ a\):操作 \(1\),将节点 \(x\) 点权增加 \(a\). \(2 \ x \ a\):操作 \(2\),将以节点 \(x\) 为根的子树中所有点的权值增加 \(a\). \(3 \ x\)

20170910校内训练

CCT 最近学校又发了n本五三题霸,BBS看到后十分高兴.但是,当他把五三拿到手后才发现,他已经刷过这些书了!他又认真地看了一会儿,发现新发的这些五三是2017版的,而他刷的是2016版的.现在他想找出所有他没有刷过的题来刷.每本五三都有m道题,并且它的特征(即它和去年版本的五三的差距)可以用一个m位二进制数来代表,二进制位上的1代表该题不同,0代表该题相同.比如4(100)就代表题目3和去年的有不同.5(101)就代表题目1和题目3和去年的有不同.而BBS热衷于给自己找麻烦,他要选择连续一段的

2017.9.17校内noip模拟赛解题报告

预计分数:100+60+60=220 实际分数:100+60+40=200 除了暴力什么都不会的我..... T1 2017.9.17巧克力棒(chocolate) 巧克力棒(chocolate)Time Limit:1000ms Memory Limit:64MB题目描述LYK 找到了一根巧克力棒,但是这根巧克力棒太长了,LYK 无法一口吞进去.具体地,这根巧克力棒长为 n,它想将这根巧克力棒折成 n 段长为 1 的巧克力棒,然后慢慢享用.它打算每次将一根长为 k 的巧克力棒折成两段长为 a

2017-4-7校内训练

丧病hzwer的ctsc训练赛 My AC:3/4 A.[Ctsc2014]企鹅QQ 思路:乱hash,我比较菜,写的丑代码各种WA+TLE,好久才A掉. #include<cstdio> #include<algorithm> using namespace std; #define ll long long #define MN 200 #define MX 6000000 #define MM 9000001 #define MOD1 890123798112473LL st

【三中校内训练】旅行

[题解] 显然的这是一道树形DP的题目 这里令f[i][0]为从i出发向以它为根的子树里走直到不能走的最大.最小价值 (不能走是什么自己阅读题目) 令s为x的儿子,w[i][j]为i和j之间的边的长度,则 f[x][0]=max(f[s][1]+w[s][i]) f[x][1]=min(f[s][0]+w[s][i]) 显然的通过这种方法,我们可以得到60分 可是,如何优化到线性呢 我们考虑一个节点x,x向某条边走的情况出现了很多次,浪费了很多时间 我们定义h[x][0/1]为从x出发,经过x的