zoukankan      html  css  js  c++  java
  • 弱鸡儿长乐爆零旅Day4

    T1 矩阵(matrix

    【题目描述】

    从前有个 n×m 的矩阵,初始时每个位置均为 0。你需要依次执行 q 个操作,每个操作会指定一行或一列,然后将该行或该列的所有元素全部赋为一个相同的值。 输出操作完成后的矩阵。

    【输入格式】

    从文件 matrix.in 中读入数据。 第一行包含三个整数 n,m,q,分别表示矩阵的大小和操作次数。 接下来 q 行,每行三个正整数 t,x,y,若 t = 1,则表示将第 x 行的所有元素赋为 y; 若 t = 2,则表示将第 x 列的所有元素赋为 y。

    【输出格式】 输出到文件 matrix.out 中。 输出 n 行,每行 m 个由空格隔开的整数,表示操作完成后的矩阵。

    【样例 1 输入】

    3 3 3

    1 1 3

    2 2 1

    1 2 2

    【样例 1 输出】

    3 1 3

    2 2 2

    0 1 0

    【样例 2 输入】

    5 3 5

    1 1 1

    1 3 1

    1 5 1

    2 1 1

    2 3 1

    【样例 2 输出】

    1 1 1

    1 0 1

    1 1 1

    1 0 1

    1 1 1

    【子任务】

    对于 20% 的数据,n×m≤25;

    对于 30% 的数据,q≤2000;

    对于 100% 的数据,n,m≤1000,n×m≤10^5,q≤10^6。 数据保证任一时刻矩阵中所有元素小于 2^31。

    对于这题 我们发现操作次数非常大 这说明很多操作都是没有用的(抽屉原理)

    为了省去不必要的操作 我们可以从后往前赋值

    遇到已经赋值的行或列就跳过 遇到已经赋值的元素也跳过

    第一篇代码是我写的(gg却ac的代码) 第二篇是标程

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 using namespace std;
     5 const int N=1e6+10;
     6 int n,m,q;
     7 int a[N],b[N];
     8 int c[N];
     9 int ans[1010][1010];
    10 bool h[1010],l[1010];
    11 int main()
    12 {
    13     freopen("matrix.in","r",stdin);
    14     freopen("matrix.out","w",stdout);
    15     scanf("%d%d%d",&n,&m,&q);
    16     for(int i=1;i<=q;i++)
    17         scanf("%d%d%d",&a[i],&b[i],&c[i]);
    18     for(int i=q;i>=1;i--){
    19         if(a[i]==1){
    20             if(h[b[i]])continue;
    21             else
    22                 for(int j=1;j<=m;j++){
    23                     if(ans[b[i]][j])continue;
    24                      ans[b[i]][j]=c[i];
    25                 }
    26             h[b[i]]=1;
    27         }    
    28         else
    29             if(a[i]==2){
    30                 if(l[b[i]])continue;
    31                 else
    32                     for(int j=1;j<=n;j++){
    33                         if(ans[j][b[i]])continue;
    34                          ans[j][b[i]]=c[i];
    35                     }
    36                 l[b[i]]=1;
    37             }        
    38     }
    39     for(int i=1;i<=n;i++){
    40         for(int j=1;j<=m;j++)
    41             printf("%d ",ans[i][j]);
    42         printf("
    ");
    43     }
    44     return 0;
    45 }
     1 #include<cmath>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<iostream>
     5 #include<algorithm>
     6 using namespace std;
     7 const int MAXN = 1000005;
     8 const int MAXn = 2005;
     9 int n, m, q, i, j, k, a[MAXn], b[MAXn];
    10 int t[MAXN], x[MAXN], y[MAXN];
    11 inline int get()
    12 {
    13     char c;
    14     while ((c = getchar()) < 48 || c > 57);
    15     int res = c - 48;
    16     while ((c = getchar()) >= 48 && c <= 57)
    17         res = res * 10 + c - 48;
    18     return res;
    19 }
    20 int main()
    21 {
    22     freopen("matrix.in", "r", stdin);
    23     freopen("matrix.out", "w", stdout);
    24     cin >> n >> m >> q;
    25     for(i = 1; i <= q; i ++)
    26     {
    27         t[i] = get(); x[i] = get(); y[i] = get();
    28         if (t[i] == 1) a[x[i]] = i;
    29         else b[x[i]] = i;
    30     }
    31     for(i = 1; i <= n; i ++)
    32     {
    33         for(j = 1; j <= m; j ++)
    34             printf("%d ", y[max(a[i], b[j])]);
    35         puts("");
    36     }
    37 }

    另外 这题数据是很多的 不写快读不行 会卡scanf

    T2 坐标系(coordinate

    【题目描述】

    从前有个平面直角坐标系。 你每次可以向上、向左或向右走,但不能经过重复的点。 求出你从坐标原点出发,走 n 步有多少种不同的方案。 答案对 10^9 + 7 取模。

    【输入格式】 从文件 coordinate.in 中读入数据。 第一行一个整数 n,表示需要走的步数。

    【输出格式】 输出到文件 coordinate.out 中。 第一行,一个整数,表示答案。

    【样例 1 输入】 2

    【样例 1 输出】 7

    【样例 1 解释】

    从 (0,0) 出发走 2 步,共有 7 种方案: (0,0)→(0,1)→(0,2) (0,0)→(0,1)→(1,1) (0,0)→(0,1)→(−1,1) (0,0)→(1,0)→(2,0) (0,0)→(1,0)→(1,1) (0,0)→(−1,0)→(−2,0) (0,0)→(−1,0)→(−1,1)

    【样例 2 输入】 3

    【样例 2 输出】 17

    【子任务】

    对于 20% 的数据,n≤10;

    对于 40% 的数据,n≤100;

    对于 60% 的数据,n≤1000;

    对于 80% 的数据,n≤10^6; 对于 100% 的数据,n≤10^9。

    只能向上 向左 向右走 不能走重复的路

    找规律 我们得到

    f[ i ] = 2 f[i - 1] + f[i - 2]

    tle—>打表是个好方法—>不会

    我们可以用矩阵乘法优化!

    矩阵加法:两个行数和列数相同的矩阵相加 新的矩阵上的元素等于前两个对应位置上的和

    矩阵乘法:与矩阵加法不同 并不要求行列数一定相等

    一个n*k的矩阵乘上k*m的矩阵会得到一个n*m的矩阵

    乘积C的第m行第n列的元素等于矩阵A的第m行的元素与矩阵B的第n列对应元素乘积之和

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstdio>
    const int mod=1e9+7;
    struct node{
        long long a[2][2];
        node(){
            a[0][0]=a[1][1]=a[1][0]=a[0][1]=0;
        }
    }qaq,qwq;
    
    node operator *(node x,node y){
        node z;
        for(int i=0;i<=1;i++)
            for(int j=0;j<=1;j++)
                for(int k=0;k<=1;k++)
                    z.a[i][j]+=(x.a[i][k]%mod)*(y.a[k][j]%mod)%mod;
        return z;
    }
    node pow(node x,int n){
        node f;
        f.a[0][0]=f.a[1][1]=1;
        while(n){
            if(n%2)
                f=f*x;
            x=x*x;
            n>>=1;
        }
        return f;
    }
    int main()
    {
        //freopen("coordinate.in","r",stdin);
        //freopen("coordinate.out","w",stdout);
        int n;
        scanf("%d",&n);
        qaq.a[0][0]=1;
        qaq.a[0][1]=3;
        qwq.a[0][0]=0;
        qwq.a[0][1]=1;
        qwq.a[1][0]=1;
        qwq.a[1][1]=2;
        node ans;
        ans=qaq*pow(qwq,n);
        printf("%lld",ans.a[0][0]%mod);
        return 0;
    }

    T3 Stall

    【题目描述】

    有 n 头牛,每头牛有个喝水时间,这段时间它将 . 独 . 占一个 Stall。现在给出每头牛 的喝水时间段,问至少要多少个 Stall 才能满足它们的要求。

    【输入格式】 从文件 a.in 中读入数据。 第一行一个正整数 n。 接下来 n 行每行两个正整数 a,b,表示每头牛的喝水时间段。

    【输出格式】 输出到文件 a.out 中。 一行一个整数,表示最少要安排多少个 Stall 才能满足所有牛的需求。

    【样例 1 输入】

    3

    1 2

    2 3

    3 4

    【样例 1 输出】

    2

    【子任务】 对于 100% 的数据,1≤n≤50000,1≤a≤b≤10^6。

    显而易见 求区间最大值

    planA 区间赋值 对于[x,y]的数每个加上1

    70分 三个点tle

    planB 差分 在a[x]的位置上++  a[y+1]位置--

    再求前缀和!

    如0 0 0 0 0 0在1~4加一

    则得到序列 0 1 0 0 0 -1

    前缀和 0 1 1 1 1 0

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int a[1000010];
    int main()
    {
        //freopen("a.in","r",stdin);
        //freopen("a.out","w",stdout);
        int n;
        cin>>n;
        int max1=0;
        for(int i=1,x,y;i<=n;i++)
        {
            scanf("%d%d",&x,&y);
            a[x]++;
            a[y+1]--;
            max1=max(max1,y+1);
        }
        int ans=0;
        int s=0;
        for(int i=1;i<=max1;i++)
        {
            s+=a[i];
            ans=max(ans,s);
        }
        printf("%d",ans);
        return 0;
    }

    T4控制开关

    【题目描述】 你有一个可以调节明暗度的灯泡,这个灯泡有 n 个明暗度,分别为 1,2,3,··· ,m。 灯泡有一个遥控器,你每按一次遥控器,假设灯泡当前亮度为 x,按一次以后就变成了 x+ 1,如果 x = m,则按一次以后变成 1。每个灯泡在设计时都有一个按钮,且有一个 舒适值 k,你可以按一次按钮,无论你现在的亮度是多少,你的亮度都会变成 k。按一 次按钮或按一次遥控器都算是操作一次。 现在给你一个序列 a1,··· ,an,一开始你的亮度是 a1,然后你要将亮度调到 a2,再 到 a3,再到 a4...... 最后到 an,完成这个亮度变化的过程会得到一个最小的操作次数 T,现在问你如何指定舒适值(舒适值指定之后不能改变),使得 T 最小。

    【输入格式】 从文件 b.in 中读入数据。 第一行两个正整数 n,m。 第二行 n 个整数,第 i 个整数表示 ai。

    【输出格式】 输出到文件 b.out 中。 输出一个整数,表示 T 的最小值。

    【样例 1 输入】

    4

    6 1 5 1 4

    【样例 1 输出】

    5

    【样例 2 输入】

    10

    10 10 9 8 7 6 5 4 3 2 1

    【样例 2 输出】

    45

    【子任务】 对于 60% 的数据,n,m≤3000; 对于 90% 的数据,n,m≤10^5; 对于 100% 的数据,2≤n,m≤10^6,1≤ai ≤m, a[i]不等于 a[i+1]。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    int n,m,a[1000005];
    long long ans=0;
    long long cnt[1000005][2];//贡献 
    long long check()//计算没有按钮的一个一个按的答案 
    {
        long long pre=0;
        for(int i=2;i<=n;i++)
        {
            if (a[i]>a[i-1]) pre+=a[i]-a[i-1];
            else pre+=a[i]+m-a[i-1];
        }
        return pre;
    }
    void change(int l, int r, int s, int d)//差分 初始值s 公差d 
    {
        cnt[l][0]+=s;
        cnt[r+1][0]-=s;
        cnt[l+1][1]+=d;
        cnt[r+1][1]-=(r-l+1)*d;
        cnt[r+2][1]+=(r-l)*d;
    }
    int main()
    {
        cin>>n>>m;
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(int i=2;i<=n;i++)
        {
            if(a[i]>a[i-1])//将要到达的位置在后面 
            {
                if(a[i]-a[i-1]>=2)//位置相差2才有贡献 5->6按钮无贡献  5->8 按钮在6无贡献 在7贡献为1 在8贡献为2 (等差数列) 
                    change(a[i-1]+2,a[i],1,1);
            }
            else//将要到达的位置在前面  
            {
                if (m-a[i-1]>=2) change(a[i-1]+2,m,1,1),change(1,a[i],m-a[i-1],1);
                if (m-a[i-1]==1) change(1,a[i],1,1);
                if (m==a[i-1])//如m=5 5->3 按钮在2开始的位置开始才有贡献 在1贡献0 2贡献1 3贡献2... 
                {
                    if(a[i]>=2)
                        change(2,a[i],1,1);
                }
            }
        }
        //统计结果  
        for(int i=2;i<=m+1;i++)
            cnt[i][0] += cnt[i-1][0],cnt[i][1]+=cnt[i-1][1];
        for(int i=2;i<=m+1;i++)
            cnt[i][1]+=cnt[i-1][1];
        //找出贡献最大的位置 
        for(int i=1;i<=m;i++)
            ans=max(ans,cnt[i][0]+cnt[i][1]);
        cout<<check()-ans<<endl;
        return 0;
    } 
  • 相关阅读:
    spring cloud项目搭建
    获取iframe的window对象
    数学杂谈 #7
    [AGC023D] Go Home
    JOISC 2021 部分题解
    [NOI2017]泳池
    [NOI2016] 循环之美
    [NOI2016] 优秀的拆分
    [LG P3676]小清新数据结构题
    [ARC113F]Social Distance
  • 原文地址:https://www.cnblogs.com/WJill/p/11247383.html
Copyright © 2011-2022 走看看