Contest:http://codeforces.com/contest/1136
第一次把一个Div2写完了,还是有点小激动的,虽然这场似乎不是很难。
A. Nastya Is Reading a Book(模拟)
题目链接:http://codeforces.com/contest/1136/problem/A
题目大意:读一本书,分n个章节。给你一个页码数,问还剩多少张没有读完(页码数在本章末尾代表这章没有读完)。
思路:模拟即可。
ACCode:
const int MAXN=1e5+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll mod=192600817;
const double EPS=1.0e-8;
const double PI=acos(-1.0);
int ans[MAXN];
int main(){
int n;
while(~scanf("%d",&n)){
int a,b;
for(int i=1;i<=n;++i){
scanf("%d%d",&a,&b);
ans[i]=b;
}int res=0,k;scanf("%d",&k);
for(int i=1;i<=n;++i){
if(ans[i]>=k){
break;
}++res;
}printf("%d\n",n-res);
}
}
B. Nastya Is Playing Computer Games(贪心)
题目链接:http://codeforces.com/contest/1136/problem/B
题目大意:给出n个井盖,每个井盖上面有一个石头。每个井盖下面有一个硬币。一个人一开始在第k个井盖上面,问最少需要多少步能够拿到所有的硬币。一步可以用来:1.将一块石头搬到相邻的井盖上 2.移动到相邻的井盖 3. 掀开井盖拿出硬币并合上井盖。
思路:很明显,发现先一直向井盖少的方向移动,然后再向另一端移动。贪心。
ACCode:
const int MAXN=1e5+10;
int n,k;
int main(){
while(~scanf("%d%d",&n,&k)){
int l=k-1,r=n-k;
int ans=2;
if(l<r){//fitst to left
ans+=3*l;//go to the laft
ans+=k-1;//return k
ans+=2;//go to next k and push pu a stone to left
ans+=2;//
ans+=3*(r-1);
}
else{//first to right
ans+=3*r;
ans+=r;
ans+=2;
ans+=2;
ans+=3*(l-1);
}printf("%d\n",ans);
}
}
C. Nastya Is Transposing Matrices(规律)
题目链接:http://codeforces.com/contest/1136/problem/C
题目大意:给出两个矩阵,判断第一个矩阵经过局部斜翻转之后能否变成第二个矩阵。可以输出YES,否则输出NO。
思路:这里说的翻转是沿着左上到右下的对角线进行,对称轴上的元素不变,对应的元素交换。然后发现还是个找规律的。因为斜对角线上的元素固定,所以所有的元素只会在同样的颜色的线之间来回变动,如图:所以我们只用比较这一对的就好了。
ACCode:
#include<stdio.h>
#include<iostream>
#include<string>
#include<algorithm>
#define ll long long
using namespace std;
const int MAXN=5e2+10;
ll a[MAXN][MAXN],b[MAXN][MAXN];
ll res[MAXN];
int n,m;
void Debug(){
cout<<"Start Debug :"<<endl<<"a: "<<endl;
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
cout<<a[i][j]<<" ";
}cout<<endl;
}cout<<"b:"<<endl;
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
cout<<b[i][j]<<" ";
}cout<<endl;
}cout<<"End Debug"<<endl;
}
// j j j
//i 1 2 3
//i 4 5 6
//i 7 8 9
//i 10 11 12
//
// j j j j
//i 1 2 3 10
//i 4 5 6 11
//i 7 8 9 12
void DealA(){
for(int i=1,j,k;i<=n;++i){
int ecnt=0,u;
for(k=i,j=1;k>=1&&j<=m;--k,++j){
res[++ecnt]=a[k][j];
}sort(res+1,res+1+ecnt);
for(k=i,j=1,u=1;k>=1&&j<=m&&u<=ecnt;--k,++j,++u){
a[k][j]=res[u];
}
}
for(int j=2,i,k;j<=m;++j){
int ecnt=0,u;
for(i=n,k=j;i>=1&&k<=m;--i,++k){
res[++ecnt]=a[i][k];
}sort(res+1,res+1+ecnt);
for(i=n,k=j,u=1;i>=1&&k<=m&&u<=ecnt;--i,++k,++u){
a[i][k]=res[u];
}
}
}
void DealB(){
for(int i=1,j,k;i<=n;++i){
int ecnt=0,u;
for(k=i,j=1;k>=1&&j<=m;--k,++j){
res[++ecnt]=b[k][j];
}sort(res+1,res+1+ecnt);
for(k=i,j=1,u=1;k>=1&&j<=m&&u<=ecnt;--k,++j,++u){
b[k][j]=res[u];
}
}
for(int j=2,i,k;j<=m;++j){
int ecnt=0,u;
for(i=n,k=j;i>=1&&k<=m;--i,++k){
res[++ecnt]=b[i][k];
}sort(res+1,res+1+ecnt);
for(i=n,k=j,u=1;i>=1&&k<=m&&u<=ecnt;--i,++k,++u){
b[i][k]=res[u];
}
}
}
int main(){
while(~scanf("%d%d",&n,&m)){
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
scanf("%lld",&a[i][j]);
}
}
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
scanf("%lld",&b[i][j]);
}
}DealA();DealB();
int flag=1;
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
if(a[i][j]!=b[i][j]){
flag=0;break;
}
}
if(flag==0) break;
}
if(flag) printf("YES\n");
else printf("NO\n");
}
}
D. Nastya Is Buying Lunch(思维,找规律)
题目链接:http://codeforces.com/contest/1136/problem/D
题目大意:给出n个人,m个关系。下面按顺序给出n个人所处的位置。然后是m个关系。u v说明:如果u在v的前面一个位置,那么v可以和v进行换位。一个人A一开始在队尾,问他最多向前移动多少?
思路:因为u在v前面一个位置才能够换位,所以可以看成有向图。又发现如果前面的一个位置i可以和A所在的位置交换(A-i)次,那么A必定能够到达i这个位置。所以我们可以直接遍历,然后向前找,刷新能够到达的位置,并且刷新A所在的位置。
ACCode:
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<map>
#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
#define Pair pair<int,int>
#define M_P(a,b) make_pair(a,b)
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
#define clean(a,b) memset(a,b,sizeof(a))// ??
//std::ios::sync_with_stdio(false);
// register
const int MAXN=3e5+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll MOD=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;
struct Node{
int v,val,nxt;
Node(int _v=0,int _val=0,int _nxt=0){
v=_v;val=_val;nxt=_nxt;
}
};
Node Edge[MAXN<<1];
int Head[MAXN],Ecnt;
int a[MAXN],num[MAXN];
int n,m;
void Intt(){
for(int i=1;i<=n;++i){
Head[i]=-1;
}Ecnt=0;
}
void Add(int u,int v,int val){
Edge[Ecnt]=Node(v,val,Head[u]);
Head[u]=Ecnt++;
}
int main(){
scanf("%d%d",&n,&m);
Intt();
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
}
for(int i=1;i<=m;++i){
int u,v;scanf("%d%d",&u,&v);
Add(v,u,1);
}
for(int i=Head[a[n]];i+1;i=Edge[i].nxt){
int temp=Edge[i].v;
num[temp]++;
}int ans=0;
for(int i=n-1;i>=1;--i){
if(num[a[i]]==n-i-ans) ans++;
else{
for(int j=Head[a[i]];j+1;j=Edge[j].nxt){
int temp=Edge[j].v;
num[temp]++;
}
}
}printf("%d\n",ans);
}
E. Nastya Hasn't Written a Legend(规律+二分+线段树)
题目链接:http://codeforces.com/contest/1136/problem/E
题目大意:给出n个数的数组A,然后是n-1个数的数组B,对于每个A[i+1]都满足A[i+1]>=A[i]+B[i]。有两个操作。
"+"操作:i位置的元素+x;"s"操作:求[l,r]区间内的元素和。
初始的A数组保证对于所有的A[i+1]>=a[i]+b[i];
思路:根据题目,我们可以这样化简:。然后就是普通线段树了。
因为.所以我们需要一个数组C来储存B的前缀和,用D来储存C的前缀和。
因为如果A[i+1]>A[i]+B[i];就不用对A[i+1]和A[i+1]后面的元素进行修改了。所以我们来确定修改的区间。因为初始A是一个有序的,我们维护之后也是有序的,因此可以用二分来找右端点。
剩下的就是普通线段树了。
ACCode:
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<map>
#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
#define Pair pair<int,int>
#define M_P(a,b) make_pair(a,b)
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
#define clean(a,b) memset(a,b,sizeof(a))// ??
//std::ios::sync_with_stdio(false);
// register
const int MAXN=1e5+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll MOD=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;
ll Tree[MAXN<<2],Lazy[MAXN<<2];
ll a[MAXN],b[MAXN],c[MAXN],d[MAXN];
int n,q;
void Build(int l,int r,int rt){
Lazy[rt]=-INF64;
if(l==r){
Tree[rt]=a[l];
return ;
}int mid=(l+r)>>1;
Build(l,mid,rt<<1);Build(mid+1,r,rt<<1|1);
Tree[rt]=Tree[rt<<1]+Tree[rt<<1|1];
}
void PushDown(int rt,int l,int r){
if(Lazy[rt]!=-INF64){
int mid=(l+r)>>1;
int ln=mid-l+1,rn=r-mid;
Tree[rt<<1]=Lazy[rt]*ln+(d[mid-1]-d[l-2]);
Tree[rt<<1|1]=Lazy[rt]*rn+(d[r-1]-d[mid-1]);
Lazy[rt<<1]=Lazy[rt<<1|1]=Lazy[rt];
Lazy[rt]=-INF64;
}
}
ll Query(int ql,int qr,int l,int r,int rt){
if(ql<=l&&r<=qr) return Tree[rt];
int mid=(l+r)>>1;
PushDown(rt,l,r);
ll ans=0;
if(ql<=mid) ans+=Query(ql,qr,l,mid,rt<<1);
if(qr>mid) ans+=Query(ql,qr,mid+1,r,rt<<1|1);
return ans;
}
void Update(int ql,int qr,ll x,int l,int r,int rt){
if(ql<=l&&r<=qr){
Tree[rt]=(r-l+1)*x+(d[r-1]-d[l-2]);
Lazy[rt]=x;
return ;
}int mid=(l+r)>>1;
PushDown(rt,l,r);
if(ql<=mid) Update(ql,qr,x,l,mid,rt<<1);
if(qr>mid) Update(ql,qr,x,mid+1,r,rt<<1|1);
Tree[rt]=Tree[rt<<1]+Tree[rt<<1|1];
}
void Refresh(int i,int x){
int l=i,r=n,mid;
ll key=Query(i,i,1,n,1);
while(l<=r){
mid=(l+r)>>1;
ll temp=Query(mid,mid,1,n,1);
//if(temp>key+x+c[mid-1]-c[i]). it's mean temp don't update.
if(temp>key+x+c[mid-1]-c[i-1]) r=mid-1;
else l=mid+1;
}Update(i,r,key+x-c[i-1],1,n,1);
}
int main(){
std::ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;++i) cin>>a[i];
for(int i=1;i<n;++i) cin>>b[i];
for(int i=1;i<n;++i) c[i]=c[i-1]+b[i];
for(int i=1;i<n;++i) d[i]=d[i-1]+c[i];
Build(1,n,1);
cin>>q;
while(q--){
string oper;int l,r;
cin>>oper>>l>>r;
if(oper=="+") Refresh(l,r);
else cout<<Query(l,r,1,n,1)<<endl;
}
}