• 模拟赛QAQ


    100 + 30 + 0 

    T1 叉叉

    题目描述

    现在有一个字符串,每个字母出现的次数均为偶数。
    接下来我们把第一次出现的字母a和第二次出现的a
    连一条线,第三次出现的和四次出现的字母a连一条线,
    第五次出现的和六次出现的字母a连一条线..
    .对其他25个字母也做同样的操作。
    现在我们想知道有多少对连线交叉。
    交叉的定义为一个连线的端点在另外一个连线的内部,
    另外一个端点在外部。
    下图是一个例子,共有三对连线交叉(我们连线的时候,只能从字符串上方经过)。

    输入输出格式

    输入格式:

    一行一个字符串。保证字符串均由小写字母组成,且每个字母出现次数为偶数次。

    输出格式:

    一个整数,表示答案。

    输入输出样例

    输入样例#1: 

    abaazooabz

    输出样例#1: 

    3

    说明

    对于30% 的数据,字符串长度不超过50。
    对于100% 的数据,字符串长度不超过100,000。

    嗯,我用树状数组做的,把每个区间起点设为1,终点设为-1,每次统计区间和,并在区间右端点处+1

    链表+前缀和O(26n)

    吐槽此题数据太弱,On^2做法都能A,学校电脑啥时候跑这么快了啊

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define lowbit(x) x&(-x)
    const int maxn =1000007;
    char a[maxn];int n,t[maxn];
    int num[maxn];
    struct node{
        int l,r;
    }edge[maxn];
    int pre[maxn],sum[maxn];
    void update(int x,int v){
        while (x<=n){
            sum[x]+=v;
            x+=lowbit(x);
        }
    }
    int query(int x){
        int ans = 0;
        while(x){
            ans+=sum[x];
            x-=lowbit(x);
        }
        return ans;
    }
    int main (){
        scanf("%s",a+1);
        n=strlen(a+1);int cnt=0;
        for(int i=1;i<=n;++i) {
            t[i]=a[i]-'a';
            if(num[t[i]]%2==1)update(i,-1),edge[pre[t[i]]].r=i,num[t[i]]++;
            else update(i,1),edge[++cnt].l=i,pre[t[i]]=cnt,num[t[i]]++;
        } 
        int ans=0;
        for(int i=1;i<=cnt;i++) {
            int l=edge[i].l,r=edge[i].r;
            ans+=query(r-1)-query(l);update(r,1);
        }
        printf("%d
    ",ans);
        return 0;
    }
    T1

    U14261 跳跳虎回家

    题目描述

    跳跳虎在外⾯出去玩忘了时间,现在他需要在最短的时间内赶回家。
    跳跳虎所在的世界可以抽象成⼀个含有 个点的图(点编号从 到 ),跳跳虎现在在 号点,跳跳虎的家在 号点。
    图上⼀共有 条单向边,通过每条边有固定的时间花费。
    同时,还存在若⼲个单向传送通道,传送通道也有其时间花费。
    传送通道⼀般来说⽐普通的道路更快,但是跳跳虎最多只能使⽤ 次。
    跳跳虎想知道他回到家的最⼩时间消耗是多少。

    输入输出格式

    输入格式:

    第一行4个整数n,m,q,k
    ( n表示点数,m表示普通道路的数量, q表示传送通道的数量,k表示跳跳虎最多使k次传送通道)
    接下来 n行每3 个整数a,b,c ,表示有1条从a到b,时间花费为c的普通道路
    接下来 q每3个整数a,b,c,表示有1条从a到b,时间花费为c的传送道路
    输出格式:
    输出一行1个整数表示最少时间消耗,如果没法回到家输出-1。

    输入输出样例

    输入样例#1: 

    5 5 2 1
    1 2 1
    1 3 2
    2 4 2
    3 4 3
    4 5 4
    1 4 1
    2 5 1

    输出样例#1: 

    2

    说明

    对于30%的数据, 1 ≤ n ≤ 500,0 ≤ m,q ≤ 2000,k = 0
    对于另外30%的数据, 1 ≤ n ≤ 500,0 ≤ m,q ≤ 2000,k = 1
    对于100%的数据 1 ≤ n ≤ 500,0 ≤ m,q ≤ 2000,0 ≤ k ≤ 

    首先k是骗人的,其次spfa瞎搞就水过去了.....吐槽此题数据太弱,spfa出队时让连向节点出队都过了....

    然而我非常BS的吧s和q输反了,然后就03了

    T
    #include<queue>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int maxn = 2007;
    struct node{
        int u,v,w,next;
        bool flag;
    }edge[maxn];
    struct Node{
        int x,k;
    }cur,nxt;
    int head[maxn],cnt;
    int k;
    void add_edge(int u,int v,int w,bool flag) {
        edge[++cnt].v=v,edge[cnt].w=w,edge[cnt].next=head[u],head[u]=cnt;
    }
    queue<Node>q;
    int n,m;
    int dis[maxn][maxn];
    bool vis[maxn][maxn];
    bool spfa() {
        memset(dis,0x3f,sizeof(dis));
        dis[1][0]=0;vis[1][0]=true;
        cur.x=1,cur.k=0;
        q.push(cur);
        while(!q.empty()) {
            cur=q.front();
            q.pop();
            int u=cur.x,kk=cur.k;
            for(int i=head[u];i;i=edge[i].next) {
                int v=edge[i].v;
                if(edge[i].flag) {
                    if(kk<k&&dis[v][kk+1]>dis[u][kk]+edge[i].w) {
                        dis[v][kk+1]=dis[u][kk]+edge[i].w;
                        if(!vis[v][kk+1]) {
                            nxt.k=kk+1;nxt.x=v;
                            q.push(nxt);
                            vis[v][kk+1]=true;
                        }
                    }
                } else {
                    if(dis[v][kk]>dis[u][kk]+edge[i].w) {
                        dis[v][kk]=dis[u][kk]+edge[i].w;
                        if(!vis[v][kk]) {
                            nxt.x=v,nxt.k=kk;
                            q.push(nxt);
                            vis[v][kk]=true;
                        }
                    }
                }
                vis[u][kk]=0;
            }
        }
        int ans=0x7fffffff;
        for(int i=0;i<=k;i++)
            ans=min(ans,dis[n][i]);
        if(ans==0x3f3f3f3f)return -1;
        else return ans;
    }
    int main() {
    //    freopen("move.in","r",stdin);
    //    freopen("move.out","w",stdout);
        int qq;
        scanf("%d%d%d%d",&n,&m,&qq,&k);    
        if(k>qq) k=qq;
        for(int u,v,w,i=1;i<=m;i++) {
            scanf("%d%d%d",&u,&v,&w);
            add_edge(u,v,w,0);
        }
        for(int u,v,w,i=1;i<=qq;i++) {
            scanf("%d%d%d",&u,&v,&w);
            add_edge(u,v,w,1);
        }
        printf("%d
    ",spfa());
        return 0;
    }
    2

    U14263 秀秀和哺噜国(cut)

    题目描述

    哺噜国里有!个城市,有的城市之间有高速公路相连。在最开始时,哺噜国里有n− 条高
    速公路,且任意两座城市之间都存在一条由高速公路组成的通路。
    由于高速公路的维护成本很高, 为了减少哺噜国的财政支出,将更多的钱用来哺育小哺噜,
    秀秀女王决定关闭一些高速公路。 但是为了保证哺噜国居民的正常生活,
    不能关闭太多的高速公路,要保证每个城市通过高速公路与至少$个城市(包括自己)相连。

    在得到了秀秀女王的指令后,交通部长华华决定先进行预调研。
    华华想知道在满足每个城市都可以与至少$个城市相连的前提下,
    有多少种关闭高速公路的方案(可以一条也不关) 。两种方案不同,
    当且仅当存在一条高速公路在一个方案中被关闭,
    而在另外一个方案中没有被关闭。 由于方案数可能很大,
    你只需输出不同方案数对786433取模后的结果即可。
    其中786433 =
    217+ 1。

    输入输出格式

    输入格式:

    从文件cut.in 中读入数据。
    输入第一行,包含两个正整数n,k。
    接下来的n − 1行,每行包含两个正整数a和b,
    表示城市a和城市b之间有一条高速公路相
    连。

    输出格式:

    输出文件到cut.out 中。
    输出一个非负整数,表示所求方案数对786433 取模后的结果。

    输入输出样例

    输入样例#1: 

    5 2
    1 2
    2 3
    3 4
    4 5

    输出样例#1:

    3

    【样例 1 解释】

    三种方案分别为:
    一条高速公路也不关闭;
    关闭城市2和城市3之间的高速公路;
    关闭城市3和城市4之间的高速公路。

    输入样例#2:

    10 2
    1 2
    1 3
    2 4
    2 5
    3 6
    3 7
    3 10
    5 8
    6 9

    输出样例#2:

    12

    【子任务】

    对于20%的数据:! ≤ 20;
    另有30%的数据:! ≤ 100;
    另有10%的数据:100;20100 ≤ !。

    说明

    空间限制:512M

    推出dp不敢写,orz认为自己写不出来,然后就没写,然后xxy讲了怎么写,然后就写了,然后就没有然后了

    然后这题需要开long long or 快速乘 然而51nod卡内存,所以只能写快速乘,然而今天模拟赛不卡!!

    dp[i][j]表示以i为根且当前联通块大小为k的方案总数,特别的,

    dp[i][0]表示割点当前点与其父亲是棵平衡树的方案总数。

    对于u的一个孩子v可以得到转移方程dp[u][j+k]=dp[u][j]*dp[v][k]

    另外dp[u][0]=Σdp[u][j](j>=题目给定的k)

    复杂度On^3,每次dp时,只枚举当前u所在子树的大小,

    每当枚举到它的其中孩子时,当前u所在子树的大小加上它孩子为根的子树的大小。

    可以理解为每一个点对只被枚举到一次,然后复杂度就编程On^2了。

    最后答案即为dp[1][0]

    #include<cstdio>
    #include<cstdlib>
    using namespace std;
    #define LL long long
    #define maxn 5007
    #define mod 1000000007
    int kkk,n;
    int head[maxn],num,dp[maxn][maxn],size[maxn],tmp[maxn];
    struct node{
        int v,next;
    }edge[maxn<<1];
    inline void add_edge(int u,int v) {
        edge[++num].v=v;edge[num].next=head[u];head[u]=num;
    }
    
    void dfs(int x,int f) {
        size[x]++;dp[x][1]=1;
        for(int i=head[x];i;i=edge[i].next) {
            int v=edge[i].v;
            if(v==f)continue;
            dfs(v,x);
            for(int j=1;j<=size[x]+size[v];++j)tmp[j]=0;
            for(int j=1;j<=size[x];++j)tmp[j]=(dp[v][0]%mod*dp[x][j]%mod)%mod;
            for(int j=1;j<=size[x];++j)
                for(int k=1;k<=size[v];++k) {
                    tmp[j+k]=(tmp[j+k]+dp[x][j]*dp[v][k]%mod)%mod;
                }
            for(int j=1;j<=size[x]+size[v];++j)dp[x][j]=tmp[j];
            size[x]+=size[v];
        }
        for(int i=kkk;i<=size[x];i++)dp[x][0]=(dp[x][0]+dp[x][i])%mod;
    }
    int main () {
    //    freopen("cut.in","r",stdin);
    //    freopen("cut.out","w",stdout);
        scanf("%d%d",&n,&kkk);
        for(int u,v,i=1;i<n;i++) {
            scanf("%d%d",&u,&v);
            add_edge(u,v);
            add_edge(v,u);
        }
        dfs(1,0);
        printf("%d
    ",dp[1][0]%mod);
        return 0;
    }
    T3
  • 相关阅读:
    Log4Net使用指南
    Log4net 写文件日志与数据库日志
    JSON-Schema 最科学的表单验证模式
    番茄时间工作法
    css 温故而知新 1px的问题
    $.ajax 温故而知新坑
    H5中滚动卡顿的问题
    横向思维
    Wd 西部数据
    使用AlloyLever来搞定开发调试发布,错误监控上报,用户问题定位
  • 原文地址:https://www.cnblogs.com/sssy/p/7716822.html
Copyright © 2020-2023  润新知