矩阵游戏(递推,数学推导)

这么简单的题才骗到40分QAQ

40分:
很简单,只要n*m扫一遍就好

80分:k^2复杂度

我们发现80分k是很小的,同时我们发现操作的顺序与结果无关,

所以我们先预处理出整个矩阵的sum和

然后对于每一个操作,例如把该行变成10倍,相当于增加九倍,所以我们k次加减....

但是例如我们第一步将第一行变成2倍,第二次将第一列变成3倍,节点1并不是的贡献2+3而是2×3

所以我们k*k扫一边再将虚假的贡献减掉(只有某个点)然后加上真实贡献

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<string>
 6 #include<set>
 7 #include<map>
 8 #include<vector>
 9 #include<cmath>
10 #define int long long
11 #define MAXN 1000101
12 #define ps push_back
13 using namespace std;
14 int read()
15 {
16     int x=0;char c=getchar();
17     while(c<'0'||c>'9')c=getchar();
18     while(c>='0'&&c<='9')
19     {
20           x=(x<<1)+(x<<3)+(c^48);
21           c=getchar();
22     }
23     return x;
24 }
25 int lie[MAXN],hang[MAXN];
26 int sum_lie[MAXN];
27 int sum_hang[MAXN];
28 int n,m;int K;int sum=0;
29 const int mod=1e9+7;
30 vector<int>v1,v2;
31 signed main()
32 {
33     //freopen("text.in","r",stdin);
34     //freopen("wa.out","w",stdout);
35     n=read();m=read();K=read();
36     for(int i=1;i<=n;++i)hang[i]=1;
37     for(int i=1;i<=m;++i)lie[i]=1;
38     for(int i=1;i<=K;++i)
39     {
40         char c;int x,y;
41         cin>>c;
42         if(c=='R')
43         {
44             x=read();y=read();
45             hang[x]=(hang[x]*y)%mod;
46         }
47         else
48         {
49             x=read();y=read();
50             lie[x]=(lie[x]*y)%mod;
51         }
52     }
53     for(int i=1;i<=n;++i)
54     {
55           sum=(sum+(i-1)*m%mod+1+mod)%mod;
56     }
57     sum_lie[1]=sum;
58     for(int i=2;i<=m;++i)
59     {
60         sum_lie[i]=(sum_lie[i-1]+n)%mod;
61         sum=(sum+sum_lie[i])%mod;
62     }
63     for(int i=1;i<=m;++i)
64         sum_hang[1]=(sum_hang[1]+i)%mod;
65     for(int i=2;i<=n;++i)
66     {
67         sum_hang[i]=(sum_hang[i-1]+m*m%mod)%mod;
68     }
69     for(int i=1;i<=n;++i)
70     {
71         if(hang[i]!=1)
72         {
73            v1.ps(i);
74            sum=(sum+(hang[i]-1)*sum_hang[i]+mod)%mod;
75         }
76     }
77     for(int j=1;j<=m;++j)
78     {
79         if(lie[j]!=1)
80         {
81             v2.ps(j);
82             sum=(sum+(lie[j]-1)*sum_lie[j]+mod)%mod;
83         }
84     }
85     for(int i=0;i<v1.size();++i)
86     {
87         for(int j=0;j<v2.size();++j)
88         {
89             int me=v1[i],you=v2[j];
90             int th=((me-1)*m+you)%mod;
91             sum=(sum+(hang[me]*lie[you]%mod-1)*th-(hang[me]-1)*th-(lie[you]-1)*th+mod)%mod;
92         }
93     }
94     printf("%lld\n",(sum+mod)%mod);
95 }
80分超时

100分 O(n+m)

我们根据一些高中数学知识发现,每一列与每一列之间的变化好像是一定的,

我们不妨先处理行上的变化,

例如第一行变成原来的3倍,那么假设原来这一行是1,2,3......现在是3,6,9.....

我们发现第一列的差值有1变为三倍,那么没一行差值相加就是列与列之间的公差

再处理列的贡献,每一列的初始值都可以递推过来,然后再乘上值的变化,统计答案即可....

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<string>
 6 #include<set>
 7 #include<map>
 8 #include<vector>
 9 #include<cmath>
10 #define int long long
11 #define MAXN 1000101
12 using namespace std;
13 int read()
14 {
15     int x=0;char c=getchar();
16     while(c<'0'||c>'9')c=getchar();
17     while(c>='0'&&c<='9')
18     {
19           x=(x<<1)+(x<<3)+(c^48);
20           c=getchar();
21     }
22     return x;
23 }
24 int lie[MAXN],hang[MAXN];
25 int n,m;int K;
26 const int mod=1e9+7;
27 signed main()
28 {
29     n=read();m=read();K=read();
30     for(int i=1;i<=n;++i)hang[i]=1;
31     for(int i=1;i<=m;++i)lie[i]=1;
32     for(int i=1;i<=K;++i)
33     {
34         char c;int x,y;
35         cin>>c;
36         if(c=='R')
37         {
38             x=read();y=read();
39             hang[x]=(hang[x]*y)%mod;
40         }
41         else
42         {
43             x=read();y=read();
44             lie[x]=(lie[x]*y)%mod;
45         }
46     }
47     int ans=0;
48     int son_cha=0;int base=0;
49     for(int i=1;i<=n;++i)
50     {
51         son_cha=(son_cha+hang[i])%mod;
52         base=(base+((i-1)*m%mod+1)*hang[i]+mod)%mod;
53     }
54     //printf("base=%lld son_cha=%lld\n",base,son_cha);
55     int sum=0;
56     for(int j=1;j<=m;++j)
57     {
58         int me=base;
59         sum=(sum+me*lie[j])%mod;
60         base=(base+son_cha)%mod;
61     }
62     printf("%lld\n",sum%mod);
63 }
View Code

 

转载于:https://www.cnblogs.com/Wwb123/p/11304916.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值