NOIP2011 DAY1,DAY2 数据,标程,题目,题解合集:
![](https://img-blog.csdn.net/20141019092414937?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvanVuamllNDM1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20141019092527156?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvanVuamllNDM1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20141019093008187?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvanVuamllNDM1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20141019093106328?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvanVuamllNDM1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20141019094110000?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvanVuamllNDM1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20141019094551453?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvanVuamllNDM1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20141019095259149?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvanVuamllNDM1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20141019095102265?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvanVuamllNDM1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20141019095512248?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvanVuamllNDM1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
http://download.csdn.net/detail/junjie435/8054741
DAY1:
p1:铺地毯
这是一道模拟题目:只需要询问一个点所以,从头到尾扫一遍就行了
#include<cstdio>
#include<cstring>
#include<iostream>
#define maxn 10010
using namespace std;
/*
模拟
*/
struct carpet
{
int x,y;
int lx,ly;
}ca[maxn];
int x,y,ans,n;
void init()
{
freopen("carpet.in","r",stdin);
freopen("carpet.out","w",stdout);
}
void readdate()
{
cin>>n;
for(int i=1;i<=n;i++)
scanf("%d%d%d%d",&ca[i].x,&ca[i].y,&ca[i].lx,&ca[i].ly);
cin>>x>>y;
}
void work()
{
ans=-1;
for(int i=1;i<=n;i++)
if(ca[i].x<=x&&ca[i].y<=y&&ca[i].x+ca[i].lx>=x&&ca[i].y+ca[i].ly>=y)
ans=i;
printf("%d\n",ans);
}
int main()
{
init();
readdate();
work();
return 0;
}
p2:选择客栈
![]()
/*这道题考试的时候抽了,样例都没过*/
给几种代码:
#include<cstdio>
#include<cstdlib>
#define maxk 51
#define maxn 200010
int sum[maxn],color[maxn],value[maxn],f[maxk+1][4];
int main()
{
freopen("hotel.in","r",stdin);
freopen("hotel.out","w",stdout);
int n,k,p,ans=0;sum[0]=0;
scanf("%d%d%d",&n,&k,&p);
for(int i=1,x;i<=n;i++)
{
scanf("%d%d",&color[i],&value[i]);
sum[i]=sum[i-1]+(value[i]<=p);//可行前缀和;
}
color[0]=maxk+1;//边界判断;
for(int i=1;i<=n;i++)
{
int tot=f[color[i]][1];
if(f[color[i]][3]<sum[i]){
tot+=f[color[i]][2];
f[color[i]][1]+=f[color[i]][2];
f[color[i]][2]=0;
}
ans+=tot;
f[color[i]][2]++;
f[color[i]][3]=sum[i]-(value[i]<=p);
}
printf("%d\n",ans);
return 0;
}
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
/*
用dp[i]维护i这种颜色在当前客栈颜色为i时可行的方案数。
*/
int n,k,p;
long long ans=0;
int num[50+10],dp[50+10];
int main()
{
freopen("hotel.in","r",stdin);
freopen("hotel.out","w",stdout);
int color,price;
scanf("%d%d%d",&n,&k,&p);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&color,&price);
if(price<=p)//当前客栈价格小于p时,之前color有多少就增加多少方案。
{
ans+=num[color];
for(int j=0;j<k;j++)dp[j]=num[j];//之后的客栈与之前的都可以配对了。
dp[color]++;//特别的,当前这个也要算上。
}
else//不然的话,当前客栈增加的方案数只有dp[color]。
{
ans+=dp[color];
}
num[color]++;
}
cout<<ans<<endl;
return 0;
}
</pre><pre name="code" class="cpp">
#include <cstdio>
#include <iostream>
using namespace std;
///
const int MAXN = 200000 + 10;
///
int n,k,p;
int col[MAXN];
int a[MAXN];
int cnt[60];
int num[MAXN];
int head[60];
int next[MAXN];
int res;
struct tree
{
int l,r,mini;
}t[800040];
///
void fre()
{
freopen("hotel.in","r",stdin);
freopen("hotel.out","w",stdout);
}
///
void read_pre()
{
scanf("%d %d %d",&n,&k,&p);
for(int i = 1;i <= n;i++)
{
int color;
int price;
scanf("%d %d",&color,&price);
col[i] = color; //记录i位置的颜色
a[i] = price; //记录i位置的价格
cnt[color]++; //颜色color出现了多少次
num[i] = cnt[color]; //当前位置的color颜色出现的个数
next[head[color]] = i; //上一个颜色为color的点的下一个点为i点
head[color] = i; //颜色color的最后一个点为i点
}
}
///
void up(int u)
{
t[u].mini = min(t[u << 1].mini,t[u << 1 | 1].mini);
}
///
void build(int u,int l,int r)
{
t[u].l = l;
t[u].r = r;
if(l == r)
{
t[u].mini = a[l];
return;
}
int mid = (l + r) >> 1;
build(u << 1,l,mid);
build(u << 1 | 1,mid + 1,r);
up(u);
}
///
int que(int u,int l,int r)
{
if(l <= t[u].l && t[u].r <= r) return t[u].mini;
int mid = (t[u].l + t[u].r) >> 1;
int ans;
if(l > mid) ans = que(u << 1 | 1,l,r);
else if(r <= mid) ans = que(u << 1,l,r);
else ans = min(que(u << 1,l,r),que(u << 1 | 1,l,r));
return ans;
}
///
int main()
{
fre();
read_pre();
build(1,1,n);
for(int i = 1;i <= n;i++)
{
int j = next[i];
while(j)
{
if(que(1,i,j) <= p)
{
res += cnt[col[i]] - num[j] + 1;
break;
}
j = next[j];
}
}
printf("%d\n",res);
return 0;
}
<pre name="code" class="cpp">#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXK 50+10
#define MAXN 200000+10
using namespace std;
struct hotel
{
int col;
int val;
}h[MAXN];
int sum[MAXN],dp[MAXK];
int temp[MAXN],col_sum[MAXN];
int n,k,p,ans=0;
void init()
{
freopen("hotel.in","r",stdin);
freopen("hotel.out","w",stdout);
}
void readdate()
{
scanf("%d%d%d",&n,&k,&p);
sum[0]=0;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&h[i].col,&h[i].val);
if(h[i].val<=p) sum[i]=sum[i-1]+1;
else sum[i]=sum[i-1]+0;
}
}
void work()
{
for(int i=1;i<=n;i++)
{
int tot=dp[h[i].col];
if(col_sum[h[i].col]<sum[i])
{
tot+=temp[h[i].col];//temp转入ans
dp[h[i].col]+=temp[h[i].col];//更新dp[col]
temp[h[i].col]=0;//temp清零
}
ans+=tot;
temp[h[i].col]++;
if(h[i].val<=p) col_sum[h[i].col]=sum[i]-1;
else col_sum[h[i].col]=sum[i]-0;
}
printf("%d\n",ans);
}
int main()
{
init();
readdate();
work();
return 0;
}
p3:mayan 游戏
这就是一道裸DFS,看都数据范围,整个人都好了
代码中有详细解释
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#define MAXN 6
#define MAXH 8
using namespace std;
/*
崩溃:结构体未清零
特殊数据
in
1
2 2 3 2 0
4 4 3 4 0
3 3 0
5 5 3 5 3 5 0
4 4 3 4 4 0
out
3 4 -1
*/
struct node
{
int h[MAXN];//当前竖列高度
int c[MAXN][MAXH];//当前列方块的map
}map;
int n,ans[MAXN][3];//用ans来记录路径
bool flag,b[MAXN][MAXH],ok=false;
void init()
{
freopen("mayan.in","r",stdin);
freopen("mayan.out","w",stdout);
}
void readdate()
{
int x;
scanf("%d",&n);
for(int i=1;i<=5;i++)
{
scanf("%d",&x);
while(x!=0)
{
map.h[i]++;
map.c[i][map.h[i]]=x;
scanf("%d",&x);
}
}
}
node clear_struct(node now)
{
for(int i=1;i<=5;i++)
{
now.h[i]=0;
for(int j=1;j<=8;j++)
now.c[i][j]=0;
}
return now;
}
bool check(node now)//是否完成
{
for(int i=1;i<=5;i++)
{
if(now.h[i]!=0)
{
return false;
}
}
return true;
}
void print()//输出路径
{
//printf("\n");
for(int i=1;i<=n;i++)
printf("%d %d %d\n",ans[i][0],ans[i][1],ans[i][2]);
ok=true;
return;
}
node move(node now)
{
node next;
next=clear_struct(next);
for(int i=1;i<=5;i++)
{
for(int j=1;j<=now.h[i];j++)
{
if(now.c[i][j]!=0&&!b[i][j])
{
next.h[i]++;
next.c[i][next.h[i]]=now.c[i][j];
}
}
}
return next;
}
node clear(node now)
{
node next;
//next=clear_struct(next);
bool flag=false;//是否进行了消除更改了地图
memset(b,0,sizeof(b));
for(int i=1;i<=5;i++)
{
for(int j=1;j<=now.h[i];j++)
{
if(i<=3)
{
if(now.c[i][j]==now.c[i+1][j]&&now.c[i][j]==now.c[i+2][j])
{
b[i][j]=b[i+1][j]=b[i+2][j]=true;
flag=true;
}
}
if(j<=now.h[i]-2)
{
if(now.c[i][j]==now.c[i][j+1]&&now.c[i][j]==now.c[i][j+2])
{
b[i][j]=b[i][j+1]=b[i][j+2]=true;
flag=true;
}
}
}
}
if(flag)
{
next=move(now);
//print();
return clear(next);//可能同时被消除所以需要再处理
}
else return now;
}
void dfs(node now,int step)
/*
对于每个节点(枚举[i][j])进行搜索
当i==5时不可向右移
当i==1时不可向左移
右移时:
当右边一列的格子高度不足j时
当前列的高度-1,右边一列的高度+1;
格子右移——>[i][j]=0;[i+1][j]=格子的数
把当前列的格子从j到h[i]都下移一位
进行消除操作
更新ans
dfs(next,step+1)
当右边一列的格子高度足够j时
把两个格子的值进行交换
进行消除操作
更新ans
dfs(next,step+1)
左移时:【与右移类似】
当左边一列的格子高度不足j时
......
当左边一列的格子高度足够j时
//其实,我们可以发现
// 当左格子与右格子交换和右格子与左格子交换是一样的
//所以为了防止TLE 于是就可以把此情况删掉
......
*/
{
node next;
//next=clear_struct(next);
flag=check(now);
if(flag==true)
{
if(step>n) print();
else return;
}
if(ok==true) return;
if(step>n) return;
for(int i=1;i<=5;i++)
{
for(int j=1;j<=now.h[i];j++)
{
if(i<5)
{
if(j>now.h[i+1])
{
next=now;
next.h[i+1]++;
next.c[i+1][next.h[i+1]]=next.c[i][j];
next.c[i][j]=0;
next.h[i]--;
for(int k=j;k<=next.h[i];k++)
next.c[i][k]=next.c[i][k+1];
next=clear(next);
ans[step][0]=i-1;
ans[step][1]=j-1;
ans[step][2]=1;
dfs(next,step+1);
if(ok==true) return;
}
else
{
next=now;
int t=next.c[i][j];
next.c[i][j]=next.c[i+1][j];
next.c[i+1][j]=t;
next=clear(next);
ans[step][0]=i-1;
ans[step][1]=j-1;
ans[step][2]=1;
dfs(next,step+1);
if(ok==true) return;
}
}
if(i>1)
{
if(j>now.h[i-1])
{
next=now;
next.h[i-1]++;
next.c[i-1][next.h[i-1]]=next.c[i][j];
next.c[i][j]=0;
next.h[i]--;
for(int k=j;k<=next.h[i];k++)
next.c[i][k]=next.c[i][k+1];
next=clear(next);
ans[step][0]=i-1;
ans[step][1]=j-1;
ans[step][2]=-1;
dfs(next,step+1);
if(ok==true) return;
}
/*
else
{
next=now;
int t=next.c[i][j];
next.c[i][j]=next.c[i-1][j];
next.c[i-1][j]=t;
next=clear(next);
ans[step][0]=i-1;
ans[step][1]=j-1;
ans[step][2]=-1;
dfs(next,step+1);
if(ok==true) return;
}
*/
}
}
}
}
int main()
{
init();
readdate();
dfs(map,1);
if(ok==false) printf("-1\n");
return 0;
}
DAY2:
p1:计算系数
明显的二次项展开;最后X^n*Y^m的系数应该为
a^n*b^m*杨辉三角中对应的系数,再取模
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define MAXN 1010
#define MOD 10007
using namespace std;
int a,b,k,n,m;
int YH[MAXN][MAXN];
int ans;
void init()
{
freopen("factor.in","r",stdin);
freopen("factor.out","w",stdout);
}
void readdate()
{
cin>>a>>b>>k>>n>>m;
YH[1][0]=1; YH[1][1]=1;
for(int i=2;i<=k;i++)//杨辉三角计算
{
YH[i][0]=1;YH[i][i]=1;
for(int j=0;j<=i-1;j++)
YH[i][j]=(YH[i-1][j-1]+YH[i-1][j])%MOD;
}
/*
for(int i=1;i<=k;i++)
{
for(int j=0;j<=i;j++)
printf("%d ",YH[i][j]);
printf("\n");
}
*/
}
void solve()
{
//计算原有系数
a%=MOD;
b%=MOD;
int temp=a;
for(int i=1;i<=n-1;i++)
a=(a*temp)%MOD;
temp=b;
for(int i=1;i<=m-1;i++)
b=(b*temp)%MOD;
ans=(a*b)%MOD;
//计算原有系数
//原有系数*杨辉三角对应的那个值
ans=(ans*YH[k][n])%MOD;
printf("%d\n",ans);
}
int main()
{
init();
readdate();
solve();
return 0;
}
p2:聪明的质监员
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int N = 200000 + 10;
int n, m, w[N], v[N], l[N], r[N];
long long s = 1e18, a[N], b[N], Y, S;
bool calc(int W) {
a[0] = b[0] = Y = 0;
for(int i=1; i<=n; i++) {
a[i] = a[i-1] + (w[i] >= W);
b[i] = b[i-1] + (w[i] >= W) * v[i];
}
for(int i=1; i<=m; i++)
Y += abs((a[r[i]] - a[l[i]-1]) * (b[r[i]] - b[l[i]-1]));
s = min(s, abs(S - Y));
return Y > S;
}
int main() {
freopen("qc.in", "r", stdin);
freopen("qc.out", "w", stdout);
scanf("%d %d %I64d", &n, &m, &S);
int p = 0, q = N, c = 1;
for(int i=1; i<=n; i++) {
scanf("%d %d", w+i, v+i);
p = min(p, w[i]), q = max(q, w[i]);
}
for(int i=1; i<=m; i++)
scanf("%d %d", l+i, r+i);
while(q - p > 1)
if(calc(c = (p + q) / 2)) p = c; else q = c;
printf("%I64d\n", s);
return 0;
}
<span style="font-size:14px;">#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#define MAXN 200000+10
#define INF 1000000
using namespace std;
int n,m;
int w[MAXN],v[MAXN];
int l[MAXN],r[MAXN];
long long S,ans=1e18;
int L,R;
long long sumj[MAXN],sumv[MAXN];
void init()
{
freopen("qc.in","r",stdin);
freopen("qc.out","w",stdout);
}
void readdate()
{
scanf("%d%d%lld",&n,&m,&S);
L=INF;R=-INF;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&w[i],&v[i]);
L=min(L,w[i]);//找到最左端 进行二分
R=max(R,w[i]);//找到最右端 进行二分
}
for(int i=1;i<=m;i++)
scanf("%d%d",&l[i],&r[i]);
R++;
}
bool check(int W)
{
long long temp=0;//以W划分所得到的检验值temp
//计算检验值
for(int i=1;i<=n;i++)
if(w[i]>=W)
{
sumj[i]=sumj[i-1]+1;
sumv[i]=sumv[i-1]+v[i];
}
else
{
sumj[i]=sumj[i-1];
sumv[i]=sumv[i-1];
}
for(int i=1;i<=m;i++)
temp+=(sumj[r[i]]-sumj[l[i]-1])*(sumv[r[i]]-sumv[l[i]-1]);
//计算检验值
bool flag;
if(S<=temp) flag=true;
else flag=false;
ans=min(ans,abs(S-temp));//更新ans
return flag;
}
void work()//二分W求得最小ans
{
while(L<=R)
{
int mid=(L+R)>>1;
if(check(mid)) L=mid+1;
else R=mid-1;
}
printf("%I64d\n",ans);
}
int main()
{
init();
readdate();
work();
return 0;
}</span>
p3:观光公交
在这里我只上代码,也有较详细的注释。
至于贪心的论述将在我下一篇博文中详细解答
#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXN 1000+10
#define MAXM 10000+10
using namespace std;
/*
贪心!!!
*/
struct NODE
{
long long t;
int from;
int to;
}person[MAXM];
int n,m,k;
int d[MAXN];//i—>i+1需要的时间
long long oversum[MAXN];//在该站点i以前有多少人下车
long long reach_time[MAXN];//车到达站点i的时间
long long latest[MAXN];//在站点i 最晚乘客到达的时间
long long s[MAXN];//如更改d[i]会影响到的站点从[i+1——>s[i]]
long long ans;
void init()
{
freopen("bus.in","r",stdin);
freopen("bus.out","w",stdout);
}
void readdate()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<n;i++)
scanf("%d",&d[i]);
for(int i=1;i<=m;i++)
{
scanf("%I64d%d%d",&person[i].t,&person[i].from,&person[i].to);
oversum[person[i].to]++;
latest[person[i].from]=max(latest[person[i].from],person[i].t);
}
return;
}
void pre()//处理最开始的reach_time,s,ans,oversum
{
//当第i-1个站台有乘客需要上车时,reach_time=latest[i-1]+d[i];
//当第i-1个站台无乘客需要上车时,reach_time=reach_time[i-1]+d[i];
//故可以得到公式:reach_time[i]=max(reach_time[i-1],latest[i-1])+d[i-1];
reach_time[1]=0;
for(int i=1;i<=n;i++)
reach_time[i]=max(reach_time[i-1],latest[i-1])+d[i-1];
//若reach_time[i+1]<=latest[i+1]时 s[i]=i+1;
//若reach_time[i+1]>latest[i+1]时 s[i]=s[i+1];
s[n]=n;s[n-1]=n;//初始最后两个站台,进行倒推
for(int i=n-2;i>1;i--)
if(reach_time[i+1]<=latest[i+1])
s[i]=i+1;
else s[i]=s[i+1];
//初始化ans;ans=(第i个人到达目的地的时间-他出发的时间)的总和
for(int i=1;i<=m;i++)
ans+=reach_time[person[i].to]-person[i].t;
//因为读入时oversum不确定,所以在这里处理oversum
for(int i=1;i<=n;i++)
oversum[i]=oversum[i-1]+oversum[i];
return;
}
void solve()
/*
每次找到最大的oversum[s[i]]-oversum[i]
在这时d[i]若减小会得到最优的ans减少
*/
{
long long maxval=0,index;
//找到最优使用加速器的地方
for(int i=1;i<=n;i++)
if(maxval<oversum[s[i]]-oversum[i])
if(d[i]>=1)
{
maxval=oversum[s[i]]-oversum[i];
index=i;
}
long long L=index,R=s[index];
d[index]--;//使用加速器
ans-=maxval;//更改ans
if(R==n) R=n-1;//特判
//再次更新reach_time
for(int i=L;i<=R;i++)
reach_time[i]=max(reach_time[i-1],latest[i-1])+d[i-1];
//再次更新s[i]
for(int i=R;i>=L;i--)
if(reach_time[i+1]<=latest[i+1])
s[i]=i+1;
else s[i]=s[i+1];
return;
}
void work()
{
//对于每一个加速器进行一次贪心
for(int i=1;i<=k;i++)
solve();
printf("%I64d\n",ans);
return;
}
int main()
{
init();
readdate();
pre();
work();
return 0;
}
小结
对于此次考试,中等题掌握较差,两天都错在了第二题。
所以,在接下来的训练中要更加注重会的题和中等题的细致。
!!!!!!