NOIp2018集训test-9-15(联考二day1)

T1.矩阵游戏

水题。每一行最后乘的数为x[i],每一列为y[i],暴力算第一行的列的贡献,每一行的列的贡献是公差为所有列的贡献之和的等差数列,然后每一行再乘上行的贡献求和即为答案。

 1 //Achen
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<cstring>
 5 #include<cstdlib>
 6 #include<vector>
 7 #include<cstdio>
 8 #include<queue>
 9 #include<cmath>
10 #include<set>
11 #include<map>
12 #define Formylove return 0
13 #define For(i,a,b) for(int i=(a);i<=(b);i++)
14 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
15 const int N=1000007,p=1e9+7;
16 typedef long long LL;
17 typedef double db;
18 using namespace std;
19 LL n,m,k,x,y;
20 LL R[N],S[N],ans,bs,rs;
21 char o[10]; 
22 
23 template<typename T>void read(T &x)  {
24     char ch=getchar(); x=0; T f=1;
25     while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
26     if(ch=='-') f=-1,ch=getchar();
27     for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
28 }
29 
30 #define ANS
31 int main() {
32 #ifdef ANS
33     freopen("game.in","r",stdin);
34     freopen("game.out","w",stdout);
35 #endif
36     read(n); read(m); read(k);
37     int up=max(n,m);
38     For(i,1,up) R[i]=S[i]=1;
39     For(i,1,k) {
40         scanf("%s",o);
41         read(x); read(y);
42         if(o[0]=='R') R[x]=R[x]*y%p;
43         else S[x]=S[x]*y%p;
44     }
45     For(i,1,m) { 
46         rs=(rs+S[i]*i%p)%p;
47         bs=(bs+S[i])%p;
48     }
49     bs=bs*m%p;
50     For(i,1,n) {
51         ans=(ans+rs*R[i]%p)%p;
52         rs=(rs+bs)%p;
53     }
54     printf("%lld\n",ans);
55     Formylove;
56 }
View Code

 

T2.跳房子

容易想到每次暴力找循环节地跳,复杂度是O(Q*循环节长度),很不幸的是循环节长度似乎是n*m级别的(我想证明循环节长度很小然后失败了)。

考虑分块做法,每一行为一块,预处理出从每一行的第一列开始走m步走到哪一行的第一列,每次先一行一行地跳(很长的也要按行找循环节),再一个一个跳。

如何修改,发现第一行能跳到某一个格子的点是连续的一些列,倒着回去找到一行的列(记录一个l,r)修改这些列即可。

注意修改一个点的权值后是修改可能跳到它的三个点。然后倒着回去的时候l,r因为会从上到下又从下到上蛇皮走位,把下标弄成从0开始然后l,r只管++--判断值的时候取模来处理,不然会debug到死也出不来。。。

  1 #include<bits/stdc++.h>
  2 #define For(i,a,b) for(int i=(a);i<=b;i++)
  3 #define Rep(i,a,b) for(int i=(a);i>=b;i--);
  4 #define Formylove return 0
  5 const int N=2007;
  6 using namespace std;
  7 typedef long long LL;
  8 typedef double db;
  9 int n,m,q,a[N][N],tx[N],vis[N],ti[N];
 10 int nx,ny;
 11 char o[10];
 12 
 13 template<typename T>void read(T &x) {
 14     char ch=getchar(); T f=1; x=0;
 15     while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
 16     if(ch=='-') f=-1,ch=getchar();
 17     for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
 18 }
 19 
 20 void walk(int &x,int &y) {
 21     int t1=a[(x+1)%n][(y+1)%m];
 22     int t2=a[x][(y+1)%m];
 23     int t3=a[(x-1+n)%n][(y+1)%m];
 24     y=(y+1)%m;
 25     if(t1>t2&&t1>t3) x=(x+1)%n;
 26     else if(t2>t1&&t2>t3) x=x;
 27     else x=(x-1+n)%n;
 28 }
 29 
 30 int mo(int x,int n) { return (x%n+n)%n; }
 31 
 32 void change(int x,int y) {
 33     x=mo(x,n); y=mo(y,m);
 34     int ex=x,ey=y;
 35     for(;;) {
 36         walk(ex,ey);
 37         if(!ey) break;
 38     }
 39     int l=x,r=x;
 40     while(y) {
 41         if(a[mo(l,n)][mo(y,m)]>a[mo(l-1,n)][mo(y,m)]&&a[mo(l,n)][mo(y,m)]>a[mo(l-2,n)][mo(y,m)])
 42             l--;
 43         else if(a[mo(l,n)][mo(y,m)]<a[mo(l-1,n)][mo(y,m)]&&(l+1>r||a[mo(l+1,n)][mo(y,m)]<a[mo(l-1,n)][mo(y,m)])) 
 44             l++;
 45         if(a[mo(r,n)][mo(y,m)]>a[mo(r+1,n)][mo(y,m)]&&a[mo(r,n)][mo(y,m)]>a[mo(r+2,n)][mo(y,m)]) 
 46             r++;
 47         else if(a[mo(r,n)][mo(y,m)]<a[mo(r+1,n)][mo(y,m)]&&(r-1<l||a[mo(r-1,n)][mo(y,m)]<a[mo(r+1,n)][mo(y,m)]))                 r--;
 48         if(l>r) break;
 49         y--;
 50     }
 51     if(l>r) return;
 52     if(r-l+1>=n) For(i,0,n-1) tx[i]=ex;
 53     else {
 54         l=mo(l,n); r=mo(r,n);
 55         if(l<=r) For(i,l,r) tx[i]=ex;
 56         else { For(i,0,r) tx[i]=ex; For(i,l,n-1) tx[i]=ex; }
 57     }
 58 }
 59 
 60 #define ANS
 61 int main() {
 62 #ifdef ANS
 63     freopen("jump.in","r",stdin);
 64     freopen("jump.out","w",stdout);
 65 #endif
 66     read(n); read(m);
 67     For(i,0,n-1) For(j,0,m-1) read(a[i][j]);
 68     For(i,0,n-1) {
 69         int x=i,y=0;
 70         For(j,0,m-1) walk(x,y);
 71         tx[i]=x;
 72     }
 73     read(q);
 74     nx=0,ny=0;
 75     while(q--) {
 76         scanf("%s",o);
 77         if(o[0]=='m') {
 78             int k;
 79             read(k);
 80             while(k&&ny!=0) {
 81                 walk(nx,ny); 
 82                 k--;
 83             }
 84             int tim=0; 
 85             vis[nx]=q;
 86             ti[nx]=tim;
 87             while(k>=m) {
 88                 k-=m;
 89                 tim++;
 90                 nx=tx[nx];
 91                 if(vis[nx]==q) {
 92                     int L=tim-ti[nx];
 93                     k=k%(L*m);
 94                     break;
 95                 }
 96                 vis[nx]=q;
 97                 ti[nx]=tim;
 98             }
 99             while(k>=m) {
100                 nx=tx[nx];
101                 k-=m;
102             }
103             while(k) {
104                 walk(nx,ny);
105                 k--;
106             }
107             printf("%d %d\n",nx+1,ny+1);
108         }
109         else {
110             int x,y,z,l,r;
111             read(x); read(y); read(z);
112             x--; y--;
113             a[x][y]=z;
114             //For(i,0,n-1) printf("%d ",tx[i]); puts("");
115             change(x,y-1);
116             change(x-1,y-1);
117             change(x+1,y-1);
118             //For(i,0,n-1) printf("%d ",tx[i]); puts("");
119         }
120     }
121     Formylove;    
122 }
View Code

 

T3优美序列
这题好神啊,我看了很久很久题解和标程也没看懂,去网上搜了一下,看见了其他学校和我们联考的巨佬的博客

第一个巨佬说:这道题可以秒切

第二个巨佬说:这是最简单的一道题

Orz Orz我被这道题和巨佬们秒了。。。什么分治,还什么归并排序的样子,什么st表,全然懵逼

然后我又继续死啃std,根据代码反推出了一个和分治似乎没有半毛钱关系的做法,不知道是std就是这样想的代码和它写的题解并没有联系还是我反推的方式太诡秘,我来口胡一下

把一个优美的序列排序后差分,每一项是1(废话)

那么考虑这样一个判断序列是否优美的方式,如果序列中存在两个数差为1,序列的权值++,如果序列的权值等于序列长度-1,则序列优美。

那么我用线段树维护序列的权值,从左到右扫整个序列,扫到i时线段树上每个叶子节点j表示j到i的序列的权值,这样每加进一个新的数x,只需要看前面有没有x-1,x+1,把1到那个位置区间+1即可。这样扫到i的时候,j~i的序列优美就转换为j的权值=i-j,把j移到左边,就把每个点j权值事先加上j,那么只需要判断权值是否等于现在的i就好了。

这样询问就可以处理了,把询问按右端点从小到大排序,在线段树上维护的同时,扫到一个右端点就把它加进当前询问的set里,set中按左端点从大到小排序。这样在i处理每个询问的时候,就是问1~l的点的权值中最靠右的一个i的位置,因为不优美的区间权值一定是小于i的,线段树只需要维护最靠右的最大值和它的位置就好了。每次查询的时候就是区间查询。如果l较大的查询到的最大值都小于i,那l较小的询问肯定也没有答案,所以set中按左端点排序,时间复杂度十分ok。

  1 //Achen
  2 #include<algorithm>
  3 #include<iostream>
  4 #include<cstring>
  5 #include<cstdlib>
  6 #include<vector>
  7 #include<cstdio>
  8 #include<queue>
  9 #include<cmath>
 10 #include<set>
 11 #include<map>
 12 #define Formylove return 0
 13 #define For(i,a,b) for(int i=(a);i<=(b);i++)
 14 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
 15 const int N=100007;
 16 typedef long long LL;
 17 typedef double db;
 18 using namespace std;
 19 int n,m,a[N],p[N],al[N],ar[N];
 20 
 21 template<typename T>void read(T &x)  {
 22     char ch=getchar(); x=0; T f=1;
 23     while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
 24     if(ch=='-') f=-1,ch=getchar();
 25     for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
 26 }
 27 
 28 struct node {
 29     int l,id;
 30     node(int l,int id):l(l),id(id){}
 31     friend bool operator <(const node&A,const node&B) {
 32         return A.l>B.l||(A.l==B.l&&A.id<B.id);
 33     }
 34 };
 35 vector<node>vc[N];
 36 
 37 #define lc (x<<1)
 38 #define rc ((x<<1)|1)
 39 #define mid ((l+r)>>1)
 40 int mx[N<<2],pos[N<<2],lz[N<<2];
 41 void build(int x,int l,int r) {
 42     mx[x]=pos[x]=r;
 43     if(l==r) return;
 44     build(lc,l,mid); build(rc,mid+1,r);
 45 }
 46 
 47 void down(int x,int l,int r) {
 48     if(!lz[x]) return;
 49     mx[lc]+=lz[x]; lz[lc]+=lz[x];
 50     mx[rc]+=lz[x]; lz[rc]+=lz[x];
 51     lz[x]=0; return;
 52 }
 53 
 54 void update(int x,int l,int r,int ql,int qr,int v) {
 55     if(l>=ql&&r<=qr) {
 56         mx[x]+=v; lz[x]+=v; return;
 57     }
 58     down(x,l,r);
 59     if(ql<=mid) update(lc,l,mid,ql,qr,v);
 60     if(qr>mid) update(rc,mid+1,r,ql,qr,v);
 61     mx[x]=max(mx[lc],mx[rc]);
 62     pos[x]=(mx[x]==mx[rc]?pos[rc]:pos[lc]);
 63 }
 64 
 65 #define pr pair<int,int>
 66 #define fi first
 67 #define se second
 68 pr qry(int x,int l,int r,int ql,int qr) {
 69     if(l>=ql&&r<=qr) 
 70         return make_pair(mx[x],pos[x]);
 71     down(x,l,r);
 72     if(qr<=mid) return qry(lc,l,mid,ql,qr);
 73     if(ql>mid) return qry(rc,mid+1,r,ql,qr);
 74     pr t1=qry(lc,l,mid,ql,qr),t2=qry(rc,mid+1,r,ql,qr);
 75     return t2>=t1?t2:t1;
 76 }
 77 
 78 int find(int l,int r,int id) {
 79     pr t=qry(1,1,n,1,l);
 80     if(t.fi==r) {
 81         al[id]=t.se; ar[id]=r;
 82         return 1;
 83     }
 84     return 0;
 85 }
 86 
 87 set<node>s;
 88 void solve() {
 89     build(1,1,n);
 90     For(i,1,n) {
 91         int up=vc[i].size();
 92         For(j,0,up-1) s.insert(vc[i][j]);
 93         if(a[i]-1&&p[a[i]-1]<i) update(1,1,n,1,p[a[i]-1],1);
 94         if(a[i]+1<=n&&p[a[i]+1]<i) update(1,1,n,1,p[a[i]+1],1);
 95         while(!s.empty()) {
 96             node t=*s.begin();
 97             if(!find(t.l,i,t.id)) break;
 98             s.erase(s.begin());
 99         }
100     }
101 }
102 
103 #define ANS
104 int main() {
105 #ifdef ANS
106     freopen("sequence.in","r",stdin);
107     freopen("sequence.out","w",stdout);
108 #endif
109     read(n);
110     For(i,1,n) {
111         read(a[i]);
112         p[a[i]]=i;
113     }
114     read(m);
115     For(i,1,m) {
116         int l,r;
117         read(l); read(r);
118         vc[r].push_back(node(l,i));
119     }
120     solve();
121     For(i,1,m) printf("%d %d\n",al[i],ar[i]);
122     Formylove;
123 }
View Code

 

 

posted @ 2018-09-20 22:10  啊宸  阅读(174)  评论(0编辑  收藏  举报