NOIP2013 DAY1,DAY2 数据,标程,题目,题解合集:
http://download.youkuaiyun.com/download/junjie435/8038671
DAY1
P1:
这道题稍微分析一下就可以得到
ans = (x + m *(10^k )) %n 10^k %n 用快速幂计算即可
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int n,m,k,o;
long long solve(int a,int b,int mm)
{
if(b==1)return a%mm;
long long x=solve(a,b/2,mm);
long long ans=((long long)(x%mm*x%mm))%mm;
if(b%2==1)ans=((long long)(ans%mm*a%mm))%mm;
return ans;
}
int main()
{
freopen("circle.in","r",stdin);
freopen("circle.out","w",stdout);
cin>>n>>m>>k>>o;
printf("%I64d\n",(o+(long long)(m*solve(10,k,n))%n)%n);
return 0;
}
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<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node
{
int pos;
int num;
}a[100010],b[100010];
int e[100010],t[100010];
int n,ans=0;
void init()
{
freopen("match.in ","r",stdin);
freopen("match.out","w",stdout);
}
bool cmp(node x,node y)
{
return x.num<y.num;
}
void pr()
{
cin>>n;
for(int i=1;i<=n;i++)
{
a[i].pos=i;
scanf("%d",&a[i].num);
}
for(int i=1;i<=n;i++)
{
b[i].pos=i;
scanf("%d",&b[i].num);
}
sort(a+1,a+n+1,cmp);
sort(b+1,b+n+1,cmp);
for(int i=1;i<=n;i++)
e[a[i].pos]=b[i].pos;
//交换后的最小结果模板是e[];
}
void merge_sort(int l,int r)
{
if(r>l)
{
int mid=(l+r)/2;
int p=l,q=mid+1,i=l;
merge_sort(l,mid);
merge_sort(mid+1,r);
while(p<=mid||q<=r)
{
if(q>r||(p<=mid&&e[q]>e[p]))t[i++]=e[p++];
else
{
t[i++]=e[q++];
ans=(ans+(mid-p+1)%99999997)%99999997;
}
}
for(int i=l;i<=r;i++)e[i]=t[i];
}
}
int main()
{
init();
pr();
merge_sort(1,n);//归并
cout<<ans;
return 0;
}
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define mm 99999997
using namespace std;
/*
先找出对应的序列,
再归并求逆序对。
*/
struct node
{
int num,fa;
}a[100000+10];
int n;
int c[100000+10];
int t[100000+10];
long long cnt;
int ans;
void msort(int l,int r)
{
if(r-l>1)
{
//int mid=l+(r-l)/2;
int mid=(l+r+1)>>1;
int p=l,q=mid,i=l;
msort(l,mid);
msort(mid,r);
while(p<mid||q<r)
{
if(q>=r||(p<mid&&c[p]<=c[q]))
{
t[i++]=c[p++];
}
else
{
t[i++]=c[q++];
cnt=((long long)(cnt+mid-p))%mm;
}
//for(int i=l;i<r;i++) c[i]=t[i];
}
for(int i=l;i<r;i++) c[i]=t[i];
}
}
bool cmp(node u,node v)
{
return u.fa<v.fa;
}
int main()
{
freopen("match.in","r",stdin);
freopen("match.out","w",stdout);
cin>>n;
for(int i=0;i<n;i++) scanf("%d",&a[i].num);
for(int i=0;i<n;i++) scanf("%d",&a[i].fa);
sort(a,a+n,cmp);
for(int i=0;i<n;i++)
{
c[i]=a[i].num;
//printf("%d ",c[i]);
}
//printf("\n");
msort(0,n);///坑~~
/*for(int i=0;i<n;i++)
{
printf("%d ",c[i]);
}*/
printf("%I64d\n",cnt);
return 0;
}
/*
6
6 5 4 3 2 1
1 2 3 4 5 6
*/
P3:
这道题当时没写过,这是一位同学的代码。我觉得较好。
直接求出最大生成树,然后询问两个节点路径上的最小值即可。求路径上的最小值,因为树是静态的,所有可以求LCA的时候顺便把路上最小值求出来。
可以用倍增算法求,比较简便
//#define _TEST _TEST
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
/////////////////////////////////////////////////
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define per(i,r,l) for(int i=r;i>=l;i--)
#define MS(arr,x) memset(arr,x,sizeof(arr))
#define LL long long
#define INE(i,u,e) for(int i=head[u];~i;i=e[i].next)
/////////////////////////////////////////////////
//O(nlogn+qlogn)
const int inf=0x3f3f3f3f;
const int maxn=10010;
const int maxm=50010;
int n,m,q;
namespace Tree//Tree声明
{ //////////////////////////////////
struct edge{int v,w,next;}e[maxm];
int head[maxn],k;
inline void adde(int u,int v,int w){e[k].v=v;e[k].w=w;e[k].next=head[u];head[u]=k++;}
bool vis[maxn];
int dis[maxn][16];
int fa[maxn][16];
int dep[maxn];
} //////////////////////////////////
namespace MST//MST声明
{ //////////////////////////////////
struct edge{int u,v,w;}e[maxm*2];
int k=0;
inline void adde(int u,int v,int w){e[k].u=u;e[k].v=v;e[k].w=w;k++;}
inline bool cmp(edge a,edge b){return a.w>b.w;}
int cnt;//联通块
int fa[maxn];
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
inline bool unio(int u,int v)
{
int fu=find(u),fv=find(v);
if(fv==fu)return 0;
fa[fu]=fv;
return 1;
}
} //////////////////////////////////
namespace MST//MST定义
{ //////////////////////////////////
void cal()
{
sort(&e[0],&e[k],cmp);
rep(i,1,n) fa[i]=i;
cnt=n;
rep(i,0,m-1)
{
if(unio(e[i].u,e[i].v)) cnt--,Tree::adde(e[i].u,e[i].v,e[i].w),Tree::adde(e[i].v,e[i].u,e[i].w);
if(cnt<=1) break;
}
}
}; //////////////////////////////////
namespace Tree//Tree定义
{ //////////////////////////////////
void dfs(int u,int father,int depth)
{
vis[u]=1;
dep[u]=depth;
INE(i,u,e)
{
int v=e[i].v;
if(v==father || vis[v]) continue;
dis[v][0]=e[i].w;
fa[v][0]=u;
dfs(v,u,depth+1);
}
}
void init()
{
MS(vis,0);
//init fa[u][0] dis[u][0]
rep(i,1,n)
if(!vis[i]) dfs(i,-1,0);
//init fa[u][j] dis[u][j]
rep(j,1,15)
{
rep(i,1,n)
{
fa[i][j]=fa[fa[i][j-1]][j-1];
}
}
rep(j,1,15)
{
rep(i,1,n)
{
dis[i][j]=min(dis[i][j-1],dis[fa[i][j-1]][j-1]);
}
}
}
int query(int u,int v)
{
if(MST::find(u)!=MST::find(v)) return -1;
int ans=inf;
while(u!=v)
{
if(dep[u]<dep[v])swap(u,v);
int tmp;
for(tmp=0;tmp<=15;tmp++) if(dep[u]-(1<<(tmp+1))<dep[v]) break;
ans=min(ans,dis[u][tmp]);
u=fa[u][tmp];
}
return ans;
}
} //////////////////////////////////
/////////////////////////////////////////////////
/////////////////////////////////////////////////
void input()
{
MS(Tree::head,-1);
MS(Tree::fa,-1);
using namespace MST;
scanf("%d%d",&n,&m);
int u,v,w;
rep(i,1,m)
{
scanf("%d%d%d",&u,&v,&w);
adde(u,v,w);
}
}
void solve()
{
///////////////////init///////////////////
int u,v;
////////////////calculate////////////////
MST::cal();//初始化最大生成树
Tree::init();//初始化倍增
scanf("%d",&q);
while(q--)
{
scanf("%d%d",&u,&v);
printf("%d\n",Tree::query(u,v));
}
/////////////////output/////////////////
}
/////////////////////////////////////////////////
int main()
{
#ifndef _TEST
freopen("truck.in","r",stdin);
freopen("truck.out","w",stdout);
#endif
input();
solve();
#ifdef _TEST
for(;;);
#endif
return 0;
}
DAY2
P1:
这是一个简单的贪心。
显然 如果h[i]>h[i-1] 那么 h[i]-h[i-1] 是不得不花新的代价来建造的。否则h[i] 不超过h[i-1]部分可以在h[i-1]部分完成的时候也顺便解决
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
/*
贪心...
*/
int n,a,ans,h;
int main()
{
freopen("block.in","r",stdin);
freopen("block.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a);
if(a>h)ans+=a-h;
h=a;
}
printf("%d\n",ans);
return 0;
}
P2:
一个模拟。想一下就可以发现。只要扫一边计算 拐角点的个数就可以了。
#include<cstdio> #include<iostream> #include<cstring> #include<cmath> using namespace std; /* 模拟!!(贪心) 当他升高后一定要降低。 当他降低后一定会升高。 ①升高—>降低—>升高—>降低 ②降低—>升高—>降低—>升高 */ int n,ans=1,flag; int a[110000]; int main() { freopen("flower.in","r",stdin); freopen("flower.out","w",stdout); cin>>n; for(int i=1;i<=n;i++) scanf("%d",&a[i]); int t=a[1]; for(int i=2;i<=n;i++) { if(a[i]>t&&flag!=1) { ans++; flag=1; } if(a[i]<t&&flag!=-1) { ans++; flag=-1; } t=a[i]; } cout<<ans<<endl; return 0; }
P3:
考试的时候画了个图。
分析了一下:
初看这道题,很容易让人想到广搜,但仔细观察数据范围,就会发现广搜是过不了的。为什么呢?因为广搜搜索了很多无用状态和重复状态。这里的重复状态不是平常所说的可通过判重剪枝的重复状态,而是每次询问都重复搜索的重复状态。为什么这么说呢,让我们分析一下。 显而易见的是,要让指定棋子移动朝一个方向移动,必须先将空格移动到指定棋子的那
个方向,然后棋子才能迈出步伐。而普通的广搜中,每次都要搜索一遍将空格移动到指定位置。并且,只有空格在指定棋子的隔壁的状态才是有用的,所以可以先预处理出棋子在[i,j]位置时,空格在k方向,要将棋子往h方向移动一格的最小步数,记为next[i][j][k][h],然后用dis[i][j][k]表示一个状态,那么next[i][j][k][h]即dis[i][j][k]状态到dis[i'][j'][h']的步数,其中i',j'为朝h方向移动后指定棋子的坐标,h'为h的反方向(想一想,为什么?),那么我们就相当于从dis[i][j][k]到dis[i'][j'][h']连了一条边权为next[i][j][k][h]的边,每次询问时,先将空格移动到指定棋子的隔壁,然后再通过各种状态之间的转移(用SPFA实现),求出到目标位置的最小移动次数.
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#define inf 0x3f3f3f3f
using namespace std;
/*
算法混杂 --!!
BFS+SPFA....
反正就是实现一个搜索+最短路
需要预处理各种数据
*/
struct node
{
int x,y,k;
};
int n,m,q;
int ex,ey,sx,sy,tx,ty;
const int dx[]={0,-1,1,0,0};
const int dy[]={0,0,0,-1,1};
int map[50][50];
int dis[50][50][5];
int d[50][50];
int next[50][50][5][5];
int vis[50][50][5];
bool check(node v)
{
if(v.x<1||v.x>n)return false;
if(v.y<1||v.y>m)return false;
return true;
}
int spfa()//find ans
{
queue<node>q;
node u,v;
for(int k=1;k<=4;k++)
if(dis[sx][sy][k]!=inf)
{
u.x=sx; u.y=sy;
u.k=k; q.push(u);
vis[u.x][u.y][u.k]=1;
}
while(!q.empty())
{
u=q.front();
q.pop();
vis[u.x][u.y][u.k]=0;
for (int i=1;i<=4;i++)
{
v.x=u.x+dx[i];
v.y=u.y+dy[i];
v.k=((i-1)^1)+1;
if(check(v)&&map[v.x][v.y]!=0&&next[u.x][u.y][u.k][i]!=inf)//判断v是否满足题意
{
if(dis[v.x][v.y][v.k]>dis[u.x][u.y][u.k]+next[u.x][u.y][u.k][i]+1) //更新dis
{
dis[v.x][v.y][v.k]=dis[u.x][u.y][u.k]+next[u.x][u.y][u.k][i]+1;
if(vis[v.x][v.y][v.k]==0)
{
q.push(v);
vis[v.x][v.y][v.k]=1;
}
}
}
}
}
int ans=inf;
for(int i=1;i<=4;i++)
if(dis[tx][ty][i]<ans)
ans=dis[tx][ty][i];
if(ans==inf)return -1;
else return ans;
}
int bfs(int sx,int sy,int tx,int ty)//处理dis
{
if(!map[sx][sy]) return inf;
if(!map[tx][ty]) return inf;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
d[i][j]=inf;
//printf("case:\n");
//printf("d[%d][%d]=%d\n",sx,sy,d[sx][sy]);
d[sx][sy]=0;
queue<node>q;
while(!q.empty()) q.pop();
node u,v; u.x=sx; u.y=sy; q.push(u);
while(!q.empty())
{
if(d[tx][ty]!=inf)
{
//printf("d[%d][%d]=%d\n",tx,ty,d[tx][ty]);
return d[tx][ty];//若更新,直接返回
}
node u=q.front(); q.pop();
for(int i=1;i<=4;i++)
{
v.x=u.x+dx[i];
v.y=u.y+dy[i];
if(check(v)&&map[v.x][v.y]!=0&&d[v.x][v.y]==inf)//判断v是否满足题意
{
d[v.x][v.y]=d[u.x][u.y]+1;//更新到达的最小步数
q.push(v);
//printf("%d-%d\n",v.x,v.y);
}
}
}
return inf;
}
void readdate()//读入并初始化数据
{
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=1;k<=4;k++)
dis[i][j][k]=inf;
scanf("%d %d %d %d %d %d",&ex,&ey,&sx,&sy,&tx,&ty);
}
int solve()
{
if(map[ex][ey]==0) return -1;//点位于固定格子上
if(map[sx][sy]==0) return -1;
if(map[tx][ty]==0) return -1;
if(sx==tx&&sy==ty) return 0;//起点和目标点重合
map[sx][sy]=0;
for(int k=1;k<=4;k++)
dis[sx][sy][k]=bfs(ex,ey,sx+dx[k],sy+dy[k]);
map[sx][sy]=1;
return spfa();
}
int main()
{
freopen("puzzle.in","r",stdin);
freopen("puzzle.out","w",stdout);
cin>>n>>m>>q;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&map[i][j]);
/*for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
printf("%d",map[i][j]);
printf("\n");
}*/
//预判每个点的下一步的下一步的连通性
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
int v=map[i][j];
map[i][j]=0;
for(int k=1;k<=4;k++)
for(int l=1;l<=4;l++)
next[i][j][k][l]=bfs(i+dx[k],j+dy[k],i+dx[l],j+dy[l]);
map[i][j]=v;
}
/*
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=1;k<=4;k++)
for(int l=1;l<=4;l++)
printf("next[%d][%d][%d][%d]=%d\n",i,j,k,l,next[i][j][k][l]);
*/
while(q--)
{
readdate();//read:EXi、EYi、SXi、SYi、TXi、TYi;
printf("%d\n",solve());
}
return 0;
}