2017-4-9四校联考

T2结论推得有点问题结果只有30,T3暴力骗了40,170/300

T1.交易

题目大意:一个人从0走到m,走1要1s,路上有n个点xi,每个点必须被经过2次,第二次要在第一次的ts之后经过才算数,求最少时间。(n<=3,000,000,0<xi<m<=10^9)

思路:f[i]表示完成前i个点后到达第i个点的最小时间,每次回头显然必须完成所有之前未完成的点,故有f[i]=min(f[j]+x[i]-x[j]+max(2*(x[i]-x[j+1]),t)),把max分开讨论,当2*(x[i]-x[j+1])<=t时,我们记最小的f[j]-x[j]-2*x[j+1]即可,2*(x[i]-x[j+1])>t时,显然只要考虑最左边的点(本人比较菜,写了单调队列),然后就O(n)了。

#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long
char B[1<<15],*S,*T,C;int X;
#define getc() (S==T&&(T=((S=B)+fread(B,1,1<<15,stdin)),S==T)?0:*S++)
inline int read()
{
    while((C=getc())<‘0‘||C>‘9‘);
    for(X=C-‘0‘;(C=getc())>=‘0‘&&C<=‘9‘;)X=X*10+C-‘0‘;
    return X;
}
#define MN 3000000
#define INF (1LL<<60)
int x[MN+5],q[MN+5],ql,qr;
ll f[MN+5],mn=INF;
int main()
{
    freopen("trade.in","r",stdin);
    freopen("trade.out","w",stdout);
    int n,m,t,i,j;
    n=read();m=read();t=read();
    for(i=1;i<=n;++i)x[i]=read();
    for(i=1,j=0;i<=n;++i)
    {
        for(;(x[i]-x[j+1])<<1>=t;++j)
        {
            mn=min(mn,f[j]-(x[j+1]<<1)-x[j]);
            if(ql<=qr&&j==q[ql])++ql;
        }
        f[i]=min(3LL*x[i]+mn,x[i]+t+(ql<=qr?f[q[ql]]-x[q[ql]]:INF));
        while(ql<=qr&&f[i]-x[i]<=f[q[qr]]-x[q[qr]])--qr;
        q[++qr]=i;
    }
    printf("%I64d",f[n]+m-x[n]);
    fclose(stdin);fclose(stdout);return 0;
}

T2.字符串

题目大意:给定两个长度为n的字符串S和T,一次变换定义为从左到右,每次令s[i]变成s[i]或s[i-1],问S变成T至少需要几次变换。(n<=3,000,000)

思路:显然从后往前,每次找到S[k[i]]=T[i]且k[i]<=i,k[i]<=k[j](j>i),令T[i]由S[k[i]]变换到最优,考虑计算这么做的最小耗时,用x[i]表示第i格在前x[i]次操作都被占用了,动态计算x[i],最大值就是答案,每次k[i]减小时,我们要用S[k[i]]从k[i]染到i,那么有x[j]=max(x[j],x[j+1])+1(k[i]<=j<i),x[i]=x[i]+1,又由于x[j]不会超过x[j+1],故x[j]=x[j+1]+1(k[i]<=j<i),相当于每次把数组左移一位(小于k[i]都为0,左移无影响,大于i不用考虑)并区间加1,我们用变量记下现在左移了多少位并记下差分即可,总复杂度O(n)。

#include<cstdio>
#include<algorithm>
using namespace std;
#define MN 3000000
char a[MN+5],b[MN+5];
int f[MN+5];
int solve()
{
    int n,i,j,s=0,p=0,ans=0;
    scanf("%d%s%s",&n,a+1,b+1);
    for(i=j=n;i;--i)
    {
        if(j>i&&a[i]!=b[i])j=i;
        if(j<=i&&a[j]!=b[i])
        {
            while(j&&a[j]!=b[i])--j;
            if(!j)return 0*puts("-1");
            ans=max(ans,++s);++f[++p+j];
        }
        s-=f[p+i];f[p+i]=0;
    }
    printf("%d",ans);
}
int main()
{
    freopen("string.in","r",stdin);
    freopen("string.out","w",stdout);
    solve();
    fclose(stdin);fclose(stdout);return 0;
}

T3.矩阵

题目大意:一个n*n的矩阵,给出m个黑格,其他全是白的,每次若(x,y)和(y,z)都是黑的,可以把(z,x)染成黑的,问最多染出多少个黑格。(n,m<=1,000,000)

思路:结论题。把这个矩阵当成邻接矩阵,题目转化n个点m条边的有向图,为若x到y有边且y到z有边,z到x也有边,问有多少条边。每个弱联通块独立,分开考虑,对这个联通块染色,染成0,1,2,满足若u到v有边,则$c[u]+1\equiv c[v]\ (mod\ 3)$,如果染色成功且三个颜色都有,那么所有0到所有1有边,所有1到所有2有边,所有2到所有0有边,因为若只有三个点,其中0到1,1到2,那么这三个点显然满足,每次加入一个点连到已有的图中,仍然满足,故由归纳法可证;若只有两个或一个颜色,显然不可能出现新的边。如果染色失败,与上面同一种思路可用归纳法证明,所有点到所有点都有连边,包括自环。然后随便写写就O(n)了。

#include<cstdio>
char B[1<<15],*S,*T,C;int X;
#define getc() (S==T&&(T=((S=B)+fread(B,1,1<<15,stdin)),S==T)?0:*S++)
inline int read()
{
    while((C=getc())<‘0‘||C>‘9‘);
    for(X=C-‘0‘;(C=getc())>=‘0‘&&C<=‘9‘;)X=X*10+C-‘0‘;
    return X;
}
#define MN 1000000
struct edge{int nx,t;}e[MN*2+5];
int h[MN+5],en,c[MN+5],o,s,f[4];
inline void ins(int x,int y)
{
    e[++en]=(edge){h[x],y};h[x]=en;
    e[++en]=(edge){h[y],x};h[y]=en;
}
void dfs(int x)
{
    ++f[c[x]];
    for(int i=h[x],p;i;i=e[i].nx,++s)
    {
        p=(c[x]+2+(i&1?1:-1))%3+1;
        if(!c[e[i].t])c[e[i].t]=p,dfs(e[i].t);
        else if(c[e[i].t]!=p)o=1;
    }
}
int main()
{
    freopen("matrix.in","r",stdin);
    freopen("matrix.out","w",stdout);
    int n,m,i;long long ans=0;
    n=read();m=read();
    while(m--)i=read(),ins(i,read());
    for(i=1;i<=n;++i)if(!c[i])
    {
        o=f[1]=f[2]=f[3]=s=0;
        c[i]=1;dfs(i);
        if(o)ans+=1LL*(f[1]+f[2]+f[3])*(f[1]+f[2]+f[3]);
        else if(f[1]&&f[2]&&f[3])ans+=1LL*f[1]*f[2]+1LL*f[2]*f[3]+1LL*f[3]*f[1];
        else ans+=s>>1;
    }
    printf("%I64d",ans);
    fclose(stdin);fclose(stdout);return 0;
}
时间: 2024-12-22 16:33:23

2017-4-9四校联考的相关文章

10.29 FJ四校联考

//四校联考Rank 16 感觉很滋磁 (虽然考的时候抱怨厦门一中出的数学题很NOIP///) 圈地 [问题描述] n根长度不一定相同的木棍,至多可以对其中一根切一刀,然后用其中的任意根围一个三角形,求三角形的最大面积.设面积为S,输出16*S^2对998244353取模后的答案.特别地,无解输出-1. 注:退化的三角形(面积为零)不被认为是三角形,答案应该为-1. [输入文件] 输入文件为tri.in. 输入文件第一行包含两个正整数n和998244353. 第二行包含n个正整数,表示每根木棍的

四校联考2017.8.20T1填算式

由于T2和T3都太高深了太巧妙了,于是只会做T1,拿了95分.现提供95分做法与满分做法 数据范围:n≤13,1≤ai≤9,0≤k≤109 大意:给n个数,在其中填+?×,允许多个数合并为一个.求使得最终结果等于k的算式数量.(这不就是我们平常玩的24点的加强版吗?) 95分解法:我们注意到对于第一个数字,其前面的操作只能为加法,对于之后的每一个数字,我们都有四种操作:在前面填加号,减号,乘号:与前面的数字合并.注意到n的值很小,于是考虑深搜.用两个数组分别记这个算式的符号和数字,当深搜到最后的

2016年9月25日四校联考

·前言:啊f**k今天早上体检,但是并不影响做题2333因为题目真的好 NOIP 啊 啊对了附中评测姬好坑啊正解强行T 23333 第一题<萝卜种子> 简要题意:小姑娘看了看狐狸的萝卜田,发现田里最多只能生长7个萝卜(多余的种子不会发芽),且4种萝卜发芽的概率是完全相同的.它们的效果分别是: 普通萝卜:生产2kg兔粮 超能萝卜:生产2kg兔粮,每种植一个其他萝卜额外产生1kg兔粮 固氮萝卜:不能用于生产兔粮,但能使每个普通萝卜和超能萝卜生产的兔粮+1kg 金坷垃萝卜:不能用于生产兔粮,但能使每

2017-3-5四校联考

szy学长出的,除了T3外都比较水 360/400. T1.小猪划船 题目大意:六只猪要过河,三只大猪ABC,三只小猪abc,其中ABCa会划船,共一只船,每次可以载2个人,给出四只猪的划船耗时,每次运载花的时间是船上耗时最小的猪的耗时乘上船上猪的个数,小猪与其对应大猪不在一起时不能与其他大猪在一起,求所有猪到对岸的最小耗时. 思路:状态最多2^7(每只猪还有船的位置),随便建图最短路或者直接搜索或者构造都能通过该题.我写的O(2^21). #include<cstdio> #include&

四校联考 推冰块

2<=n,m<=10^9,0<=k<=50000. 我们发现有用的格子不是很多,经过详细的分类讨论,只有这些格子是有用的: 四个角,以及障碍物(或减速带)本身和上下左右四个方向,以及障碍物所在行列(及±1的)的头尾两个. 那么我们只要把所有 障碍 和 减速带 按x-y和y-x排序一下,对于每一个有用的格子二分一下找到往左和往右会推到哪里,连边完暴力bfs即可. #include <iostream> #include <stdio.h> #include &

20170814四校联考

啊啊啊啊啊啊NOIAu大神ysy出题虐菜出人命啦!爆tan(pi/4)啦!被害者家属情绪稳定. ysy大佬谁敢D啊,NOIAu1st了,只适合D人了. 还是IOIAu的大佬体谅人,我还那么蒟蒻呢~ 闲话不说,上题目: T1: 宝石(gem) [题目描述]有 n 座城市,编号为 1~n,第 i 座城市里宝石的交易价格为 ai.当你经过第 i 座城市时,你可以以 ai 的价格购买或卖出一个宝石.在任意时刻,你最多只能携带一个宝石.有 m 次操作,操作分为两种:(1) 给定l,r,询问依次经过编号为l

2017-2-26福建四校联考

哎我好菜啊 从来没打过表的萌新这次想打个表结果打太多了长度超限了(后来发现根本没必要打表) ---------我是分割线 A.矩形 给定一个2*n的矩形,每个位置有一个正权值,你要把它恰好分成m个矩形,使得所有矩形的和的最大值最小并求出最小的最大值. n<=100000 m<=100 题解: 首先很显然m只是一个附加条件,如果你能分<m段,那么你一定能分m段. 看到最大值最小,最小值最大的问题,很自然想到二分答案. 然后我们用一个dp来check.用f[i]表示前i*2的矩形至少要分几段

20170820四校联考

来看看IOIAu巨神zzx的名言 不用循环输入就会狗啊哥哥! 上题目: T1: 填算式(expr) [题目描述] 填算式是一种简单的数学游戏,可以形式化描述如下:n 个数字a1; a2; -- ; an 排成一排(1<= ai<=9),相邻两个数字之间有一个空格.你可以在每个空格内填入运算符+- * 之一,也可以不填,要求得到的算式的运算结果等于k.你的任务是计算有多少种不同的正确算式.比如n = 3,3 个数字为2; 2; 2,k = 24时,有两种不同的正确算式:22 + 2 = 24,2

四校联考——20170730模拟赛

今天3题都很丧. 我只会T1,所以我很弱 T1要有桶排序,不然会T,被卡常 做法就是先排序,然后前缀和乱搞 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define ll long long #pragma o1 using namespace std; inline int read(){ int x=0;char c=getchar();bool t

【四校联考】点

[题目描述] 有n个点,初始时没有边.有m个操作,操作分为两种: (1) 在i和j之间增加一条无向边,保证1<=i,j<=n. (2) 删去最后添加的k条边,保证k<=当前边数. 你想要知道最多能选取多少个两两不连通的点,以及选取的方案数.在每次操作后输出这两个值.方案数对998244353取模. [输入数据] 第一行两个整数n,m.接下来m行每行第一个数表示操作类型,接下来2或1个数表示i,j或k. [输出数据] 对于每个操作,输出一行两个整数,用一个空格隔开. [样例输入] 3 7