比赛的时候只过了ABC题,F题爆了三发,TLE,后来发现F题把<=1改成<=2就A了,┭┮﹏┭┮

A:n个格子,k个有水,每次有水的格子会往左右倒水,问多少轮后所有格子都有水。

题解:模拟。。

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<map>
#include<set>
#include<queue>
#include<vector>
#define mp make_pair
using namespace std;
typedef long long LL;
typedef pair<int,int> pa;
const int N=206;
int n,a[N];
bool b[N],c[N];
int Write[20],WRI;
void judge(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
int read(){int d=0,f=1; char c=getchar(); while (c<'0'||c>'9'){if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') d=d*10+c-48,c=getchar(); return d*f;}
void write(int x){if (!x){putchar('0'); return;}if (x<0) putchar('-'),x=-x;for (WRI=1;x;x/=10,WRI++) Write[WRI]=x%10;for (int i=WRI-1;i;i--) putchar((char)(Write[i]+48));}
int main()
{
    //judge();
    int T=read();
    while (T--)
    {
        n=read(); int k=read();
        for (int i=1;i<=200;i++) b[i]=0;
        for (int i=1;i<=k;i++) b[read()]=1;
        int ans=0;
        for (;;ans++)
        {
            bool bo=1;
            for (int i=1;i<=n;i++) if (!b[i]) bo=0; 
            if (bo) break;
            for (int i=1;i<=n;i++)
                if (b[i])
                {
                    if (i-1) c[i-1]=1;
                    if (i+1<=n) c[i+1]=1;
                    c[i]=1;
                }
            for (int i=1;i<=n;i++) b[i]=c[i],c[i]=0;
        }
        printf("%d\n",ans+1);
    }
    return 0;
}
View Code

B:有n(n<=1000)个学生,第i个学生在l[i]时刻来到queue最后,同一时刻来的学生编号小的在前,每个时刻队头的学生能拿到tea,若第i个学生r[i]时刻不能拿到tea,他就会离开队伍。问每个学生拿到tea的时刻(不能拿到的输出0)

题解:一开始没想清楚就写了,WA,改完后发现自己是个ZZ,也算是模拟题吧。。。

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
#include<set>
#include<queue>
#include<vector>
#define mp make_pair
using namespace std;
typedef long long LL;
typedef pair<int,int> pa;
const int N=1010;
struct node{int x,y,id;}a[N];
int n,T,h,t,q[N],ans[N];
int Write[20],WRI;
void judge(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
int read(){int d=0,f=1; char c=getchar(); while (c<'0'||c>'9'){if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') d=d*10+c-48,c=getchar(); return d*f;}
void write(int x){if (!x){putchar('0'); return;}if (x<0) putchar('-'),x=-x;for (WRI=1;x;x/=10,WRI++) Write[WRI]=x%10;for (int i=WRI-1;i;i--) putchar((char)(Write[i]+48));}
bool cmp(node a,node b){return a.x<b.x||a.x==b.x&&a.id<b.id;}
int main()
{
    //judge();
    int T=read();
    while (T--)
    {
        n=read();
        memset(a,0,sizeof a);
        memset(q,0,sizeof q);
        for (int i=1;i<=n;i++) a[i].x=read(),a[i].y=read();
        for (int i=1;i<=n;i++) a[i].id=i;
        sort(a+1,a+1+n,cmp);
        int tt=a[1].x; bool bo=0;
        for (int p=1;p<=n;p++)
        {
            int x=p;
            if (tt>a[x].y) ans[x]=0;
            else
            {
                if (tt<a[x].x) tt=a[x].x;
                ans[x]=tt;
                tt++;
            }
        }
        for (int i=1;i<=n;i++) printf("%d ",ans[i]); puts("");
    }
    return 0;
}
View Code

C:给一个n个数的排列(n<=200000),告诉你每个位置能否与后一位交换,问能否通过若干次交换使序列有序。

题解:从大到小枚举,可行的话必须要这个数当前位置到应在位置-1都是可交换的,做完了。

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<map>
#include<set>
#include<queue>
#include<vector>
#define mp make_pair
using namespace std;
typedef long long LL;
typedef pair<int,int> pa;
const int N=200010;
int n,a[N],b[N],sum[N];
char s[N];
int Write[20],WRI;
void judge(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
int read(){int d=0,f=1; char c=getchar(); while (c<'0'||c>'9'){if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') d=d*10+c-48,c=getchar(); return d*f;}
void write(int x){if (!x){putchar('0'); return;}if (x<0) putchar('-'),x=-x;for (WRI=1;x;x/=10,WRI++) Write[WRI]=x%10;for (int i=WRI-1;i;i--) putchar((char)(Write[i]+48));}
int main()
{
    //judge();
    n=read();
    for (int i=1;i<=n;i++) a[i]=read(),b[a[i]]=i;
    scanf("%s",s+1);
    for (int i=n;i>=1;i--) sum[i]=sum[i+1]+s[i]-'0';
    for (int i=n;i>=1;i--)
        if (i>b[i]&&sum[b[i]]-sum[i]!=i-b[i])
        {
            puts("NO");
            return 0;
        }
    puts("YES");
    return 0;
}
View Code

E:有一个n个点m条边的无向图,求其补图的联通块个数及每个块的大小(n,m<=200000)

题解:bfs,每次bfs时,设u=q.front(),将原图中与u相连的点标记为与u相连,这样剩下的点就是补图中与u相连的点,将它们加入联通块和队列,用链表优化。

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<map>
#include<set>
#include<queue>
#include<vector>
#define mp make_pair
using namespace std;
typedef long long LL;
typedef pair<int,int> pa;
const int N=200010;
struct E{int to,nxt;}e[N<<1];
int n,m,head[N],cnt,l[N],r[N],ans[N],ans_cnt,fa[N];
bool b[N];
int Write[20],WRI;
void judge(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
int read(){int d=0,f=1; char c=getchar(); while (c<'0'||c>'9'){if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') d=d*10+c-48,c=getchar(); return d*f;}
void write(int x){if (!x){putchar('0'); return;}if (x<0) putchar('-'),x=-x;for (WRI=1;x;x/=10,WRI++) Write[WRI]=x%10;for (int i=WRI-1;i;i--) putchar((char)(Write[i]+48));}
void add(int x,int y){e[++cnt]=(E){y,head[x]}; head[x]=cnt;}
void addedge(int x,int y){add(x,y); add(y,x);}
void del(int x){b[x]=1; r[l[x]]=r[x]; l[r[x]]=l[x];}
void bfs(int ljj)
{
    queue<int>q;
    int sum=1;
    q.push(ljj);
    while (!q.empty())
    {
        int u=q.front(); q.pop();
        for (int i=head[u];i;i=e[i].nxt)
        {
            int v=e[i].to;
            fa[v]=u;
        }
        for (int i=r[0];i<=n;i=r[i])
            if (fa[i]!=u&&!b[i])
            {
                q.push(i);
                del(i);
                sum++;
            }
    }
    ans[++ans_cnt]=sum;
}
int main()
{
    //judge();
    n=read(); m=read();
    for (int i=1;i<=m;i++) addedge(read(),read());
    for (int i=0;i<=n;i++) l[i]=i-1,r[i]=i+1;
    for (int i=1;i<=n;i=r[i]) if (!b[i]) 
    {
        del(i);
        bfs(i);
    }
    sort(ans+1,ans+1+ans_cnt);
    write(ans_cnt); puts("");
    for (int i=1;i<=ans_cnt;i++) write(ans[i]),putchar(' ');
    return 0;
}
View Code

F:设D(n)表示n的因数个数,给n个数,q次操作,1 l r表示将[l,r]的每个数a[i]变为D(a[i]),2 l r表示输出sum(l,r)。(n,q<=3E5,a[i]<=1E6)

题解:套路题,线段树,x变为D(x)的次数不会很多,修改就暴力下去,每个节点记录其代表区间是否全部<=2,遇到标记了的区间就不用下去了,查询直接做。比赛的时候脑子不清楚,写了<=1,愉快地T了。。。

#include<cstdio>
typedef long long LL;
const int N=300010,M=1000010;
struct node{int l,r; LL s; bool b;}a[N<<2];
int n,m,f[M];
int Write[20],WRI;
inline int read(){int d=0,f=1; char c=getchar(); while (c<'0'||c>'9'){if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') d=d*10+c-48,c=getchar(); return d*f;}
inline void write(LL x){if (!x){putchar('0'); return;}if (x<0) putchar('-'),x=-x;for (WRI=1;x;x/=10,WRI++) Write[WRI]=x%10;for (int i=WRI-1;i;i--) putchar((char)(Write[i]+48));}
inline void build(int i,int l,int r)
{
    a[i].l=l; a[i].r=r; a[i].b=0;
    if (l==r) {a[i].s=read(); if (a[i].s<=2) a[i].b=1; return;}
    int mid=(l+r)>>1;
    build(i<<1,l,mid); build(i<<1|1,mid+1,r);
    a[i].s=a[i<<1].s+a[i<<1|1].s;
    a[i].b=a[i<<1].b&&a[i<<1|1].b;
}
inline void update(int i,int l,int r)
{
    if (a[i].b) return;
    if (a[i].l==a[i].r) {a[i].s=f[a[i].s]; if (a[i].s<=2) a[i].b=1; return;}
    int mid=(a[i].l+a[i].r)>>1;
    if (r<=mid) update(i<<1,l,r);
    else if (l>mid) update(i<<1|1,l,r);
    else update(i<<1,l,mid),update(i<<1|1,mid+1,r);
    a[i].s=a[i<<1].s+a[i<<1|1].s;
    a[i].b=a[i<<1].b&&a[i<<1|1].b;
}
inline LL query(int i,int l,int r)
{
    if (l<=a[i].l&&a[i].r<=r) return a[i].s;
    int mid=(a[i].l+a[i].r)>>1;
    if (r<=mid) return query(i<<1,l,r);
    else if (l>mid) return query(i<<1|1,l,r);
    else return query(i<<1,l,mid)+query(i<<1|1,mid+1,r);
}
int main()
{
    n=read(); m=read();
    for (int i=1;i<=1000000;i++)
        for (int j=1;i*j<=1000000;j++)
            f[i*j]++;
    build(1,1,n);
    while (m--)
    {
        int op=read(),l=read(),r=read();
        if (op==1) update(1,l,r);
        else printf("%lld\n",query(1,l,r));
    }
    return 0;
}
View Code