弱鸡儿长乐爆零旅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("\n");
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;
} 

 

posted @ 2019-07-25 22:18  Markill  阅读(300)  评论(0编辑  收藏  举报