noip2013 简要题解

原创 2013年12月04日 22:40:37

day1  P1

ans = (x + m *(10^k )) %n   10^k %n 用快速幂计算即可

#include <iostream>
using namespace std;
long long n,m,k,x;
long long power(long long x, long long y, long long n){
     long long ans = 1;
     while (y){
           if(y & 1) ans = ( ans * x) % n;
           y/=2;  x = (x * x) %n;
     }
     return ans;
}
int main()
{
    cin >> n >> m >> k >> x;
    cout << (x + m * ( power( 10 , k , n)) % n) %n << endl;

    return 0;
}

 

day1 P2

(ai-bi)^2 = ai*ai +bi*bi-2ai*bi  最小化结果 显然就是最大化  ai *bi的和,因此我们要找每个ai对应的bi是谁,显然假设ai< aj  那么一定满粗  bi< bj

因为不难证明 如果bi>bj 交换对应关系能使得值更优

那么显然最后问题变成了如何移动b使得移动次数最少,显然根据a我们可以知道每个b最终所在的位置。假设最终所在位置是实际的大小(假设那样是对b的有序化),那么

这个问题就可以转变为求逆序对的问题,就是在那种相对大小的情况下,当前b数组的逆序对。

#include <iostream>
#include <algorithm>
using namespace std;
const int mod = 99999997;
const int maxn = 1000000+10;
struct Node{
       int v,pos;
       bool operator<(const Node & o)const{
            return v < o.v;
       }
}a[maxn],b[maxn];
int c[maxn],id[maxn];
void insert(int x){
     for (; x<maxn; x+=(x & (-x))) c[x]++;
}
int  getSum(int x){
     int ans = 0;
     for (; x; x-=(x & (-x))) ans+=c[x];
     return ans;
}
int main()
{
    int n;
    cin>>n;
    for (int i = 0; i < n; ++i){
        cin >> a[i].v; a[i].pos = i+1;
    }
    for (int i = 0; i < n; ++i){
        cin >> b[i].v; b[i].pos = i+1;
    }
    sort(a,a+n);
    sort(b,b+n);
    for (int i = 0; i <n; ++i){
        id[a[i].pos] = b[i].pos;
    }
    int ans = 0;
    for (int i = n; i>=1; --i){
        ans = (ans+ getSum(id[i])) % mod;
        insert(id[i]);
    }
    cout << ans << endl;
    return 0;
}



day1 P3

直接求出最大生成树,然后询问两个节点路径上的最小值即可。求路径上的最小值,因为树是静态的,所有可以求LCA的时候顺便把路上最小值求出来。

可以用倍增算法求,比较简便

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int INF = 0x7fffffff;
const int maxn = 10000+10;
const int maxm = 50000+10;
struct Edge{
       int x,y,w;
       bool operator<(const Edge & o)const{
            return w > o.w;
       }
}e[maxm];
vector<int> v[maxn];
int f[maxn][20],L[maxn][20],father[maxn],dep[maxn];
bool vis[maxn];
int n,m,q,x,y,ans;
void  addEdge(int x,int y, int w){
      v[x].push_back(y); 
      v[x].push_back(w);
      v[y].push_back(x);
      v[y].push_back(w);
}
int  find(int x){
     if (father[x]==0) return x;
     return (father[x] = find( father[x]) );
}
void dfs(int x, int fa){
     vis[x] = true;
     int len = v[x].size();
     for (int i = 0; i < len; i+=2){
         int y = v[x][i];
         int w = v[x][i+1];
         if (y!=fa){
             dep[y] = dep[x] + 1;
             L[y][0] = w;
             f[y][0] = x;
             dfs(y,x);
         }
     }
}
void  getMaxPath(){
      for (int j = 1; j < 16; ++j)
          for (int i = 1; i <= n; ++i){
              f[i][j] = f[f[i][j-1]][j-1];
              L[i][j] = min(L[i][j-1], L[f[i][j-1]][j-1]);
          }
}
int   getAns(int x, int y){
      if (dep[x] < dep[y]) swap(x,y);
      int delta = dep[x] - dep[y];
      for (int i = 15; i >=0; i--)
          if (delta & (1<<i)) {
              ans = min(L[x][i],ans);
              x = f[x][i];
          }  
      if (x==y) return x;
      for (int i = 15; i >=0; i--)
          if (f[x][i] != f[y][i]){
             ans = min(ans,L[x][i]);
             ans = min(ans,L[y][i]);
             x = f[x][i];
             y = f[y][i];
          }
      ans = min(ans,L[x][0]);
      ans = min(ans,L[y][0]);
      return f[x][0];
}
int main()
{
    cin>> n >> m;
    for (int i =  0 ; i< m; ++i){
        scanf("%d %d %d", &e[i].x,&e[i].y,&e[i].w);
    }
    sort(e,e+m);
    for (int i = 0; i < m;++i){
        int x = find(e[i].x);
        int y = find(e[i].y);
        if (x!=y){
              addEdge(e[i].x,e[i].y,e[i].w);
              father[x] = y;
        }
    }
    memset(father,0,sizeof(father));
    for (int i = 1; i <= n; ++i) 
        for (int j = 0; j <16; ++j) L[i][j] = INF;
    memset(vis, 0, sizeof(vis));
    for (int i = 1; i <= n; ++i) 
    if (!vis[i]){
        dep[i] = 0;
        dfs(i,0);
    }
    getMaxPath();
    cin >> q;
    for (int i = 1; i <= q; ++i){
        scanf("%d %d",&x, &y);
        ans = INF;
        if (find(x)!=find(y)) {
           int lca = getAns(x,y);
           if (lca == 0) ans = -1;
        }
        printf("%d\n",ans);
    }
    return 0;
}



day2  P1

一个贪心即可,显然 如果h[i]>h[i-1] 那么 h[i]-h[i-1] 是不得不花新的代价来建造的。否则h[i] 不超过h[i-1]部分可以在h[i-1]部分完成的时候也顺便解决

#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
    int n, h ;
    cin >> n;
    long long ans = 0;
    int  last = 0;
    for (int i = 0; i < n ; ++i){
        scanf("%d", &h);
        if ( h > last) ans += h-last;
        last = h;
    }
    cout << ans << endl;
    return 0;
}


 

day2 P2

 f[i][1] = max(f[j][0])+1 a[j]<a[i];
 f[i][0] = max(f[j][1])+1 a[j]>a[i];

显然类似于LIS问题, 用树状数组或者线段树优化到nlogn 之后想了一下 貌似只要扫一边计算 拐角点的个数就可以了。

#include <iostream>
#include <cstdio>
#include <string>
using namespace std;
const int maxm = 1000000+10;
const int maxn = 100000+10;
int c0[maxm],c1[maxm], h[maxn];
int n;
void insert(int *c, int x,int val){
     for (;x<maxm; x+=x&(-x)) c[x] = max(c[x],val);
}
int getMax(int *c, int x){
    if (!x) return 0;
    int ans = 0;
    for (; x; x-=x&(-x)) ans = max(ans,c[x]);
    return ans;
}
int main()
{
    cin>> n ;
    int ans = 1;
    for (int i = 1; i <= n ; ++i){
        scanf("%d", &h[i]); h[i]++;
    }
    insert(c0,h[1],1);
    insert(c1,maxm-1-h[1],1);
    for (int i = 2; i <= n; ++i){
        int tmp = getMax(c0,h[i]-1);
        ans = max(ans,tmp+1);
        insert(c1,maxm-1-h[i],tmp+1);
        
        tmp = getMax(c1,maxm-1-h[i] -1);
        ans = max(ans,tmp+1);
        insert(c0,h[i],tmp+1);
    }
    cout << ans << endl;
    return 0;
}


day2 P3

一道很经典的广搜题 ,需要优化,就是空格一旦确定的情况下,那么其他1的所有位置也确定,并且目标位置的一定必须要把空格先移动过去,

那么这个空格的移动的最少次数我们可以先通过bfs预处理出来。

这样复杂度就是预处理n^4 + qn^2

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
using namespace std;
const int inf = 0x7fffffff;
const int maxn = 30+5;
const int  dir[4][2]={0,-1,0,1,-1,0,1,0};
int mat[maxn][maxn], dis[maxn][maxn][4], step[maxn][maxn][4][4];
int d[maxn][maxn];
int n,m,q,test,ex,ey,sx,sy,tx,ty;
struct node{
       int x,y;
};
struct node2{
       int x,y,k;
};
bool	inside(int x, int y){
	return (x>=1 && x <= n && y>= 1 && y <= m);
}
int spfa(){
	queue<node2> q;
	while (!q.empty()) q.pop();
	for (int k = 0; k < 4; ++k)
		if (dis[sx][sy][k]!=inf)
			q.push((node2){sx,sy,k});
	while (!q.empty()){	
		int x = q.front().x;
		int y = q.front().y;
		int k = q.front().k;
		//cout <<x<<" "<<y<<" "<<k<<" "<<dis[x][y][k]<<endl;
		q.pop();
		for (int i = 0;  i < 4; ++i){
			int _x = x + dir[i][0];
			int _y = y + dir[i][1];
			if (inside(_x,_y))
			if (mat[_x][_y])
			if (step[x][y][k][i]!=inf)
			if (dis[_x][_y][i ^ 1] > dis[x][y][k]+step[x][y][k][i] +1) {
				dis[_x][_y][i ^ 1] = dis[x][y][k]+step[x][y][k][i] +1;
				q.push((node2){_x,_y,i ^ 1 });
			}
		}
	}
	int ans = inf;
	for (int i = 0; i < 4; ++i)
		if (dis[tx][ty][i] < ans) ans = dis[tx][ty][i];
	return (ans==inf?-1:ans);
}
int bfs(int sx, int sy, int tx, int ty){
	if (!mat[sx][sy]) return inf;
	if (!mat[tx][ty]) return inf;
	for (int i = 1; i <= n; ++i)
		for (int  j = 1; j <=m; ++j) d[i][j] = inf;
	d[sx][sy] = 0;
	queue<node> q;
	while (!q.empty()) q.pop();
	q.push((node){sx,sy});
	while (! q.empty()){
		if (d[tx][ty] != inf) return d[tx][ty];
		int x = q.front().x;
		int y = q.front().y;
		q.pop();
		for (int i = 0; i < 4; ++i){
			int _x = x+dir[i][0];
			int _y = y+dir[i][1];
			if (inside(_x,_y))
			if (mat[_x][_y] && d[_x][_y]==inf){
				d[_x][_y] = d[x][y]+1;
				q.push((node){_x,_y});
			}
		}
	}
	
	return inf;
}
void init(){
	for (int i = 1; i <= n; ++i )
		for (int j = 1; j <= m ; ++j){
			int v = mat[i][j];
			mat[i][j] = 0;
			for (int k = 0; k < 4; ++k)
				for (int l = 0; l < 4; ++l)
					step[i][j][k][l] = bfs(i+dir[k][0],j+dir[k][1],
                    i+dir[l][0],j+dir[l][1]);
			mat[i][j] = v;
		}
}	
int 	getAns(){
	scanf("%d %d %d %d %d %d", &ex,&ey,&sx,&sy,&tx,&ty);
	if (sx ==tx && sy== ty) return 0;
	if (sx==ex && sy==ey) return -1;
	if (!inside(ex,ey) || !inside(sx,sy) || !inside(tx,ty)) return -1;
	if (!mat[ex][ey] || !mat[sx][sy] || !mat[tx][ty]) return -1;
	for (int i = 1; i <= n; ++i)
		for (int j =1 ; j <= m; ++j)
			for (int k = 0; k < 4; ++k)
					dis[i][j][k] = inf;
	mat[sx][sy] = 0;
	for (int k = 0; k < 4; ++k){
		 dis[sx][sy][k] = bfs(ex,ey,sx+dir[k][0],sy+dir[k][1]);
         //cout << k << " "<<dis[sx][sy][k]<<endl;	
    }
	mat[sx][sy] = 1;

	return spfa(); 
}
int main()
{
    cin >> n >> m >> test;
    for (int i = 1;  i <= n; ++i)
        for (int j = 1; j <= m ;++ j)
            cin>> mat[i][j];
    init();
    while (test--)
		printf("%d\n",getAns());
		
    return 0;
}


 

 

noip2013普及组解题报告

第一题:记数问题 题目描述 Description 试计算在区间1到n的所有整数中,数字x(0≤x≤9)共出现了多少次?例如,在1到11中,即在1、2、3、4、5、6、7、8、9、...
  • u012746396
  • u012746396
  • 2013年12月29日 12:36
  • 4160

NOIP 2013 提高组题解 【附AC代码】

NOIP2013 提高组题解
  • u012274244
  • u012274244
  • 2013年11月19日 15:28
  • 2732

noip2013详细题解

  • 2014年07月07日 12:33
  • 289KB
  • 下载

第十九届全国信息学分区联赛noip2013普及组试题数据题解

  • 2013年11月19日 14:17
  • 9.14MB
  • 下载

noip2016提高&普及组简要题解

提高组两天的难易程度都是1-3-2Day1toy乱搞模拟running首先对于一个人(s,t),我们把这条路径拆分为(s,lca)与(lca,t),其中lca为s与t的最近公共祖先 先看(s,lca...
  • jokerwyt
  • jokerwyt
  • 2016年11月25日 21:42
  • 609

NOIP 2015 简要题解

[Day 1] T1 神奇的幻方 送分模拟题,但是遇到了一个非常流弊的学弟:
  • ycdfhhc
  • ycdfhhc
  • 2015年11月08日 21:28
  • 5660

NOIP2016 简要题解

如此水的数据,由于太弱没有AK,真是太菜了。 DAY1: T1:这道题我只记得mogician和mengbier了,其余都忘光辣~~~。 T2:考场上写了lca后的O(NlogN)的做法,但还是A了。...
  • lych_cys
  • lych_cys
  • 2016年12月04日 15:25
  • 783

NOIP2013货车运输 题解

题目描述  A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。  现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下...
  • zzx2015
  • zzx2015
  • 2015年08月11日 17:59
  • 2953

NOIP2013提高组 华容道 题解+代码

华容道……Description小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次。于是,他想到用编程来完成华容道:给定一种局面,华容道是否根本就无法完成,如果能完成,最少需要多少时间。小...
  • u011056504
  • u011056504
  • 2016年03月30日 20:46
  • 1821

【NOIP2013模拟】Vani和Cl2捉迷藏 题解&代码

原题Descriptionvani和cl2在一片树林里捉迷藏……这片树林里有N座房子,M条有向道路,组成了一张有向无环图。树林里的树非常茂密,足以遮挡视线,但是沿着道路望去,却是视野开阔。如果从房子A...
  • liyizhixl
  • liyizhixl
  • 2016年06月03日 19:56
  • 5871
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:noip2013 简要题解
举报原因:
原因补充:

(最多只允许输入30个字)