矩陣遊戲
【NOIP提高組A】題目描述
Input
Output
Sample Input
Sample Input1
3 4 4
R 2 4
S 4 1
R 3 2
R 2 0
Sample Input2
2 4 4
S 2 0
S 2 3
R 1 5
S 1 3
Sample Output
Sample Output1
94
Sample Output2
80
Data Constraint
題解
最樸素的算法是過不了的。
然後發現了這道題操作的順序是不影響最後的結果的,所以對每行每列的操作可以一起存下來。
既是定義爲第行上的數變成了原來的倍,爲第列上的數變成了原來的倍
顯然開始全爲1,然後隨着輸入更新就行了。
並且我們可以通過一個數的座標算出它的值。
所以先分別算出和然後再分別統計答案再求和就行了
代碼
#include<cstdio>
#include<cstring>
#include<algorithm>
typedef long long LL;
using namespace std;
const int MAXN=int(1e6+5);
#define mod int(1e9+7)
LL n,m,k;
LL x,y;
LL H[MAXN],L[MAXN];
LL S0,S1;
int main()
{
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
char s[10];
scanf("%lld%lld%lld",&n,&m,&k);
LL x,y;
for(LL i=1;i<=n;i++)
H[i]=1;
for(LL i=1;i<=m;i++)
L[i]=1;
while(k--) {
scanf("%s%lld%lld",s,&x,&y);
if(s[0]=='R') H[x]=H[x]*y%mod;
else L[x]=L[x]*y%mod;
}
for(LL i=1;i<=n;i++)
S0=(S0+(i-1)*m%mod*H[i]%mod)%mod;
for(LL i=1;i<=m;i++)
S1=(S1+i*L[i]%mod)%mod;
LL ans=0;
for(LL i=1;i<=m;i++)
ans=(ans+S0*L[i]%mod)%mod;
for(LL i=1;i<=n;i++)
ans=(ans+S1*H[i]%mod)%mod;
printf("%lld",ans);
}
【NOIP提高組A】跳房子
題目描述
Input
Output
Sample Input
4 4
1 2 9 3
3 5 4 8
4 3 2 7
5 8 1 6
4
move 1
move 1
change 1 4 100
move 1
Sample Output
4 2
1 3
1 4
Data Constraint
題解
受到中山紀中講題時常不喜歡給正解的影響(雖然這道題給了),好吧我太菜了,講一下我考場上的思路。因爲,所以我們需要找到一個環使變小。再看看找環這個思路雖然容易被卡,但是還算可做,所以就決定直接找環。
具體實現上爲了減少在更改後重新找環的過程,我們把一堆弄成一塊,一堆看成一塊,然後每次更改後的第一次重新找環就行了,據說是可以過85因爲數據太水了沒有專門卡這個(其實可以卡成)
代碼
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int MAXN=int(2e3+5);
int n,m,Qm;
int a[MAXN][MAXN];
bool vis[MAXN][MAXN];
struct node {
int x,y;
node() {};
node(int X,int Y):x(X),y(Y){}
}t[5];
vector<node>Q;
int hug;
node Up(node u) {return node((u.x+n-2)%n+1,u.y%m+1);}
node Mid(node u) {return node(u.x,u.y%m+1);}
node Down(node u) {return node(u.x%n+1,u.y%m+1);}
bool cmp(node p,node q) {
return a[p.x][p.y]>a[q.x][q.y];
}
void Build(node u) {
t[1]=Up(u),t[2]=Mid(u),t[3]=Down(u);
sort(t+1,t+4,cmp);
node nx=t[1];
if(vis[nx.x][nx.y]) {
for(int i=0;i<Q.size();i++)
if(Q[i].x==nx.x&&Q[i].y==nx.y)
hug=i;
return;
}
vis[nx.x][nx.y]=1;
Q.push_back(nx);
Build(nx);
}
int main()
{
freopen("jump.in","r",stdin);
freopen("jump.out","w",stdout);
node now=node(1,1);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&a[i][j]);
scanf("%d",&Qm);
char s[10];
int x,y,z,k;
int d=0;
bool f=1;
for(int i=1;i<=Qm;i++) {
scanf("%s",s);
if(s[0]=='c') {
scanf("%d%d%d",&x,&y,&z);
a[x][y]=z;
f=1;
}
else {
scanf("%d",&k);
if(f) {
while(Q.size()!=0) {
node q=Q.back();
Q.pop_back();
vis[q.x][q.y]=0;
}
Q.push_back(now);d=0;
vis[now.x][now.y]=1;
Build(now);
}
int siz=Q.size();
if(d+k<siz) d+=k,k=0;
if(d+k>=hug&&k) k-=hug-d,d=hug;
if(k)
d=hug+(d-hug+1+k)%(siz-hug)-1;
now=Q[d];
printf("%d %d\n",now.x,now.y);
f=0;
}
}
}
【NOIP提高組A】優美序列
題目描述
Input
Output
Sample Input
Sample Input1
7
3 1 7 5 6 4 2
3
3 6
7 7
1 3
Sample Input2
10
2 1 4 3 5 6 7 10 8 9
5
2 3
3 7
4 7
4 8
7 8
Sample Output
Sample Output1
3 6
7 7
1 7
Sample Output2
1 4
3 7
3 7
3 10
7 10
Data Constraint
題解
大概來說,據說,可能可以這樣說,這個方法可有卡過(有人寫出了985ms)。
就是對原數列我們維護一個它的映射,既對存
所以對中一段區間來說,找到他的,再找到它在上的值,假如對應了
所以中中的都要取,我們找到其中位置最大的和最小的,就是重新把值對應回位置,這樣就得到了一個新的中的區間,不斷重複這個操作直到找到一個合法區間就行了。
簡單說一下,合法區間就是值對應位置和位置都是值都是匹配的。
最大值最小值搞一個表就行了。
代碼
#pragma GCC optimize(2)
#include<cmath>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
int read(){
int x=0;bool f=0;char c=getchar();
while(c<'0'||c>'9')f|=c=='-',c=getchar();
while(c>='0'&&c<='9')x=x*10+(c^48),c=getchar();
return f?-x:x;
}
void print(int x){
if(x>9) print(x/10);
putchar(x%10+'0');
}
#define MAXN 100000
int N,M;
int A[MAXN+5],pos[MAXN+5];
int Log2[MAXN+5],Pow2[MAXN+5];
int Ansl,Ansr;
#define LOG 17
int STMax0[MAXN+5][LOG+5],STMax1[MAXN+5][LOG+5];
int STMin0[MAXN+5][LOG+5],STMin1[MAXN+5][LOG+5];
void Init(){
for(int i=1;i<=N;i++)
Log2[i]=log2(i);
for(int i=0;i<=LOG;i++)
Pow2[i]=1<<i;
for(int i=1;i<=N;i++)
STMax0[i][0]=STMin0[i][0]=A[i],
STMax1[i][0]=STMin1[i][0]=pos[i];
for(int j=1;j<=LOG;j++)
for(int i=1;i+Pow2[j-1]<=N;i++)
STMax0[i][j]=max(STMax0[i][j-1],STMax0[i+Pow2[j-1]][j-1]),
STMin0[i][j]=min(STMin0[i][j-1],STMin0[i+Pow2[j-1]][j-1]),
STMax1[i][j]=max(STMax1[i][j-1],STMax1[i+Pow2[j-1]][j-1]),
STMin1[i][j]=min(STMin1[i][j-1],STMin1[i+Pow2[j-1]][j-1]);
}
int QueryMax0(int l,int r){
int k=Log2[r-l+1];
return max(STMax0[l][k],STMax0[r-Pow2[k]+1][k]);
}
int QueryMax1(int l,int r){
int k=Log2[r-l+1];
return max(STMax1[l][k],STMax1[r-Pow2[k]+1][k]);
}
int QueryMin0(int l,int r){
int k=Log2[r-l+1];
return min(STMin0[l][k],STMin0[r-Pow2[k]+1][k]);
}
int QueryMin1(int l,int r){
int k=Log2[r-l+1];
return min(STMin1[l][k],STMin1[r-Pow2[k]+1][k]);
}
void Solve(int l,int r){
int Max=QueryMax0(l,r),Min=QueryMin0(l,r);
int L=QueryMin1(Min,Max),R=QueryMax1(Min,Max);
Max=QueryMax0(L,R),Min=QueryMin0(L,R);
if(Max-Min==R-L){
Ansl=L,Ansr=R;
return;
}
Solve(L,R);
}
int main(){
freopen("sequence.in" ,"r", stdin);
freopen("sequence.out","w",stdout);
N=read();
for(int i=1;i<=N;i++)
pos[A[i]=read()]=i;
Init();
M=read();
while(M--){
int L=read(),R=read();
Solve(L,R);
print(Ansl),putchar(' '),print(Ansr),putchar('\n');
}
}