NOIP提高组1560~1570集合答案

1860:【10NOIP提高组】乌龟棋
小明过生日的时候,爸爸送给他一副乌龟棋当作礼物。

乌龟棋的棋盘是一行NN 个格子,每个格子上一个分数(非负整数)。棋盘第1 格是唯一的起点,第NN 格是终点,游戏要求玩家控制一个乌龟棋子从起点出发走到终点。



乌龟棋中MM 张爬行卡片,分成44 种不同的类型(MM 张卡片中不一定包含所有44 种类型的卡片,见样例),每种类型的卡片上分别标有1、2、3、41、2、3、4 四个数字之一,表示使用这种卡片后,乌龟棋子将向前爬行相应的格子数。游戏中,玩家每次需要从所有的爬行卡片中选择一张之前没有使用过的爬行卡片,控制乌龟棋子前进相应的格子数,每张卡片只能使用一次。游戏中,乌龟棋子自动获得起点格子的分数,并且在后续的爬行中每到达一个格子,就得到该格子相应的分数。玩家最终游戏得分就是乌龟棋子从起点到终点过程中到过的所有格子的分数总和。

很明显,用不同的爬行卡片使用顺序会使得最终游戏的得分不同,小明想要找到一种卡片使用顺序使得最终游戏得分最多。

现在,告诉你棋盘上每个格子的分数和所有的爬行卡片,你能告诉小明,他最多能得到多少分吗?
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
 
using namespace std;
 
int n, m;
int a[10010], b, num[10010];	//a是每个格子的分数,num存四种牌各自的数量 
int f[42][42][42][42];	//四维分别表示一步两步三步四步的牌的使用数量 
 
int main() {
	scanf( "%d%d", &n, &m );
	for( int i = 1; i <= n; i++ )
		scanf( "%d", &a[i] );
	for( int i = 1; i <= m; i++ ) {
		scanf( "%d", &b );
		num[b]++;
	}
	f[0][0][0][0] = a[1];	//初始化,最开始获得第一个格子的分数
	//枚举各种牌 
	for( int i = 0; i <= num[1]; i++ )
		for( int j = 0; j <= num[2]; j++ )
			for( int k = 0; k <= num[3]; k++ )
				for( int l = 0; l <= num[4]; l++ ) {
					int step = i + 2 * j + 3 * k + 4 * l + 1;	//当前所能前进的步数 
					if( i )
						f[i][j][k][l] = max( f[i][j][k][l], f[i - 1][j][k][l] + a[step] );
					if( j )
						f[i][j][k][l] = max( f[i][j][k][l], f[i][j - 1][k][l] + a[step] );
					if( k )
						f[i][j][k][l] = max( f[i][j][k][l], f[i][j][k - 1][l] + a[step] );
					if( l )
						f[i][j][k][l] = max( f[i][j][k][l], f[i][j][k][l - 1] + a[step] );
				}
	printf( "%d", f[num[1]][num[2]][num[3]][num[4]] );				
	return 0;	//功德圆满 
}
1861:【10NOIP提高组】关押罪犯
SS 城现有两座监狱,一共关押着NN 名罪犯,编号分别为1∼N1∼N。他们之间的关系自然也极不和谐。很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突。我们用“怨气值”(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之间的积怨越多。如果两名怨气值为cc 的罪犯被关押在同一监狱,他们俩之间会发生摩擦,并造成影响力为cc 的冲突事件。

每年年末,警察局会将本年内监狱中的所有冲突事件按影响力从大到小排成一个列表,然后上报到SS 城ZZ 市长那里。公务繁忙的ZZ 市长只会去看列表中的第一个事件的影响力,如果影响很坏,他就会考虑撤换警察局长。

在详细考察了NN 名罪犯间的矛盾关系后,警察局长觉得压力巨大。他准备将罪犯们在两座监狱内重新分配,以求产生的冲突事件影响力都较小,从而保住自己的乌纱帽。假设只要处于同一监狱内的某两个罪犯间有仇恨,那么他们一定会在每年的某个时候发生摩擦。那么,应如何分配罪犯,才能使ZZ 市长看到的那个冲突事件的影响力最小?这个最小值是多少?

【输入】
每行中两个数之间用一个空格隔开。

第一行为两个正整数NN 和MM,分别表示罪犯的数目以及存在仇恨的罪犯对数。

接下来的MM 行每行为三个正整数aj,bj,cjaj,bj,cj,表示ajaj 号和bjbj 号罪犯之间存在仇恨,其怨气值为cjcj。数据保证 1≤aj<bj≤N1≤aj<bj≤N ,0<cj≤1,000,000,0000<cj≤1,000,000,000 ,且每对罪犯组合只出现一次。

【输出】
共11 行,为ZZ 市长看到的那个冲突事件的影响力。如果本年内监狱中未发生任何冲突事件,请输出00。

【输入样例】
4 6
1 4 2534
2 3 3512
1 2 28351
1 3 6618
2 4 1805
3 4 12884
【输出样例】
3512
#include<iostream>
#include<cstring>
#define maxn 20010
#define maxm 100010<<1
using namespace std;

//Grape
int tot=1, head[maxn], Next[maxm], ver[maxm], weight[maxm];
void AddEdge(int x, int y, int z){
    ver[++tot] = y;  weight[tot] = z;
    Next[tot] = head[x];  head[x] = tot;
    ver[++tot] = x;  weight[tot] = z;
    Next[tot] = head[y];  head[y] = tot;
}
int col[maxn], now;
bool dfs(int x){//染色
    for(int i = head[x]; i; i = Next[i]){
        int y = ver[i], w = weight[i];
        if(w > now){//只染大于mid的边构成的图
            if(col[x]==col[y])return false;
            if(col[y])continue;
            col[y] = 3-col[x];
            if(!dfs(y))return false;
        }
    }
    return true;
}

//Timu
int n, m;
bool check(int x){
    memset(col,0,sizeof(col));
    now = x;
    for(int i = 1; i <= tot; i++){
        if(!col[ver[i]] && weight[i]>x){
            col[ver[i]] = 1;
            if(dfs(ver[i]))continue;
            return false;
        }
    }
    return true;
}

int main(){
    cin>>n>>m;
    for(int i = 1; i <= m; i++){
        int x, y, z;
        cin>>x>>y>>z;
        AddEdge(x,y,z);
    }
    int l = 0, r = 1<<30;
    while(l < r){
        int mid = l+r>>1;
        if(check(mid))r = mid;
        else l = mid+1;
    }
    cout<<l<<'\n';
    return 0;
}
 
 

1862:【10NOIP提高组】引水入城
在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠。该国的行政区划十分特殊,刚好构成一个NN 行MM 列的矩形,如上图所示,其中每个格子都代表一座城市,每座城市都有一个海拔高度。

为了使居民们都尽可能饮用到清澈的湖水,现在要在某些城市建造水利设施。水利设施有两种,分别为蓄水厂和输水站。蓄水厂的功能是利用水泵将湖泊中的水抽取到所在城市的蓄水池中。因此,只有与湖泊毗邻的第11 行的城市可以建造蓄水厂。而输水站的功能则是通过输水管线利用高度落差,将湖水从高处向低处输送。故一座城市能建造输水站的前提,是存在比它海拔更高且拥有公共边的相邻城市,已经建有水利设施。

由于第NN 行的城市靠近沙漠,是该国的干旱区,所以要求其中的每座城市都建有水利设施。那么,这个要求能否满足呢?如果能,请计算最少建造几个蓄水厂;如果不能,求干旱区中不可能建有水利设施的城市数目。

【输入】
每行中两个数之间用一个空格隔开。

输入的第一行是两个正整数NN 和MM,表示矩形的规模。

接下来NN 行,每行MM 个正整数,依次代表每座城市的海拔高度。

【输出】
输出有两行。如果能满足要求,输出的第一行是整数1,第二行是一个整数,代表最少建造几个蓄水厂;如果不能满足要求,输出的第一行是整数00,第二行是一个整数,代表有几座干旱区中的城市不可能建有水利设施。

【输入样例】
2 5
9 1 5 4 3
8 7 6 1 2
【输出样例】
1
1
【提示】
【样例说明】

只需要在海拔为99 的那座城市中建造蓄水厂,即可满足要求。

【输入输出样例2】

输入:

3 6
8 4 5 6 4 4
7 3 4 3 3 3
3 2 2 1 1 2
输出:

1
3
#include <bits/stdc++.h>
using namespace std;
 
const int fx[5]={0,1,0,-1,0};
const int fy[5]={0,0,1,0,-1};
const int Max=505;
int n,m,head,tail,ans,sum,now=1;
int num[Max][Max],vis[Max][Max],l[Max][Max],r[Max][Max];
struct shu{int x,y;};
shu p[250005];
struct qj{int l,r;};
qj c[Max];
 
inline int get_int()
{
	int x=0,f=1;
	char c;
	for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
	if(c=='-') f=-1,c=getchar();
	for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
	return x*f;
}
 
inline bool comp(const qj &a,const qj &b){return a.l!=b.l ? a.l<b.l : a.r<b.r;}
inline void bfs(int a[Max][Max],int X,int Y,int v,int tag)
{
	if(a[X][Y]) return;
	head=0,tail=1;
	p[1].x=X,p[1].y=Y,a[X][Y]=v;
	while(head<tail)
	{
	  head++;
	  int x=p[head].x,y=p[head].y;
	  for(int i=1;i<=4;++i)
	  {
	  	int x1=x+fx[i],y1=y+fy[i];
	  	if(a[x1][y1]||x1<1||x1>n||y1<1||y1>m) continue;
	  	if(!tag&&num[x1][y1]>=num[x][y]) continue;
	  	if(tag&&num[x1][y1]<=num[x][y]) continue;
	  	tail++,a[x1][y1]=a[x][y];
	  	p[tail].x=x1,p[tail].y=y1;
	  }
	}
}
 
int main()
{
	n=get_int(),m=get_int();
	for(int i=1;i<=n;++i)
	  for(int j=1;j<=m;++j) num[i][j]=get_int();
	for(int i=1;i<=m;++i) bfs(vis,1,i,1,0);
	for(int i=1;i<=m;++i) if(!vis[n][i]) sum++;
	if(sum) {cout<<"0\n"<<sum;return 0;}
	for(int i=1;i<=m;++i) if(!l[n][i]) bfs(l,n,i,i,1);  //妙啊
	for(int i=m;i>=1;--i) if(!r[n][i]) bfs(r,n,i,i,1);  //妙啊
	for(int i=1;i<=m;++i) c[i].l=l[1][i],c[i].r=r[1][i];
	sort(c+1,c+m+1,comp);
	int to=0;
	for(int i=1;i<=m;++i)
	{
	  if(now>=c[i].l) to=max(to,c[i].r);
	  else ans++,now=to+1,to=max(to,c[i].r);
	}
	if(now-1<m) ans++;
	cout<<"1\n"<<ans;
	return 0;
}
 
 

1863:【11NOIP提高组】铺地毯
为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯。一共有nn 张地毯,编号从11 到nn。现在将这些地毯按照编号从小到大的顺序平行于坐标轴先后铺设,后铺的地毯覆盖在前面已经铺好的地毯之上。

地毯铺设完成后,组织者想知道覆盖地面某个点的最上面的那张地毯的编号。注意:在矩形地毯边界和四个顶点上的点也算被地毯覆盖。

【输入】
输入共 n+2n+2 行。

第一行,一个整数 nn,表示总共有nn 张地毯。

接下来的 nn 行中,第i+1i+1 行表示编号ii 的地毯的信息,包含四个正整数a,b,g,ka,b,g,k,每两个整数之间用一个空格隔开,分别表示铺设地毯的左下角的坐标(a,ba,b)以及地毯在xx轴和yy 轴方向的长度。

第 n+2n+2 行包含两个正整数xx 和yy,表示所求的地面的点的坐标(x,yx,y)。

【输出】
输出共 11 行,一个整数,表示所求的地毯的编号;若此处没有被地毯覆盖则输出−1−1。

【输入样例】
3
1 0 2 3
0 2 3 3
2 1 3 3
2 2
【输出样例】
3
#include <bits/stdc++.h>
using namespace std;
typedef struct Carpet
{
	int xmin, xmax, ymin, ymax;
	Carpet(){}
	Carpet(int a, int b, int g, int k)//用左下角坐标及横纵方向长度来初始化4个成员变量 
    {
        xmin = a;
        ymin = b;
        xmax = a + g;
        ymax = b + k;
    }
	bool contains(int x, int y)//地毯是否盖住(x,y)点
	{
		return x >= xmin && x <= xmax && y >= ymin && y <= ymax;
	}
}Carpet;

int main()
{
	int n, a, b, g, k, x, y; 
	Carpet carp[10005];
	cin>>n;
	for(int i = 1; i <= n; ++i)
	{
		cin>>a>>b>>g>>k;
		carp[i] = Carpet(a, b, g, k);
	}
	cin>>x>>y;
	for(int i = n; i >= 1; --i)//从后向前遍历,找到的第一个包含x,y点的地毯就是这一点最上面的地毯 
	{
		if(carp[i].contains(x, y))//若地毯i覆盖了点x,y 
		{
		    cout<<i;
		    return 0;
		}
	}
	cout<<-1;//若没有被地毯覆盖 
	return 0;
}
1864:【11NOIP提高组】选择客栈
丽江河边有 nn 家很有特色的客栈,客栈按照其位置顺序从11 到nn 编号。每家客栈都按照某一种色调进行装饰(总共kk 种,用整数0∼k−10∼k−1 表示),且每家客栈都设有一家咖啡店,每家咖啡店均有各自的最低消费。

两位游客一起去丽江旅游,他们喜欢相同的色调,又想尝试两个不同的客栈,因此决定分别住在色调相同的两家客栈中。晚上,他们打算选择一家咖啡店喝咖啡,要求咖啡店位于两人住的两家客栈之间(包括他们住的客栈),且咖啡店的最低消费不超过p。

他们想知道总共有多少种选择住宿的方案,保证晚上可以找到一家最低消费不超过pp元的咖啡店小聚。

【输入】
共n+1n+1 行。

第一行三个整数 n,k,pn,k,p,每两个整数之间用一个空格隔开,分别表示客栈的个数,色调的数目和能接受的最低消费的最高值;

接下来的 nn 行,第i+1i+1 行两个整数,之间用一个空格隔开,分别表示ii 号客栈的装饰色调和ii 号客栈的咖啡店的最低消费。

【输出】
只有一行,一个整数,表示可选的住宿方案的总数。

【输入样例】
5 2 3
0 5
1 3
0 2
1 4
1 5
【输出样例】
3
#include <bits/stdc++.h>
using namespace std;
 
const int Max=200005;
int n,m,k,p,pre,sum1,sum2;
long long ans;
int f[Max][17],color[Max],Log[Max];
 
inline int get_int()
{
	int x=0,f=1;
	char c;
	for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
	if(c=='-') f=-1,c=getchar();
	for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
	return x*f;
}
 
inline int mn(int x,int y){return x < y ? x : y;}
 
inline void pr()
{
	for(int i=2;i<=n;i++) Log[i]=Log[i>>1]+1;
	for(int j=1;(1<<j)<=n;j++)
	  for(int i=1;i+(1<<j)-1<=n;i++)
	    f[i][j]=mn(f[i][j-1],f[i+(1<<j-1)][j-1]);
}
 
inline int low(int l,int r)
{
	int len=Log[r-l+1];
	return min(f[l][len],f[r-(1<<len)+1][len]);
}
 
inline int solve(int id)
{
	sum1=sum2=pre=0;
	for(int i=1;i<=n;i++) if(color[i]==id) sum1++;
	ans+=1ll*sum1*(sum1-1)/2;
	for(register int i=1;i<=n;i++)
	  if(color[i]==id)
	  {
	  	if(!pre) {pre=i;continue;}
	  	if(low(pre,i)>p) sum2++;
	  	else ans-=1ll*sum2*(sum2+1)/2,sum2=0;
	  	pre=i;
	  }
	if(sum2) ans-=1ll*sum2*(sum2+1)/2;
}
 
int main()
{
	n=get_int(),k=get_int(),p=get_int();
	for(int i=1;i<=n;i++) color[i]=get_int(),f[i][0]=get_int();
	pr();
	for(int i=0;i<k;i++) solve(i);
	cout<<ans<<"\n";
	return 0; 
}
1865:【11NOIP提高组】Mayan 游戏
Mayan puzzle 是最近流行起来的一个游戏。游戏界面是一个77 行55 列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放在其他方块之上。游戏通关是指在规定的步数内消除所有的方块,消除方块的规则如下:

1、每步移动可以且仅可以沿横向(即向左或向右)拖动某一方块一格:当拖动这一方块时,如果拖动后到达的位置(以下称目标位置)也有方块,那么这两个方块将交换位置(参见输入输出样例说明中的图6 到图7);如果目标位置上没有方块,那么被拖动的方块将从原来的竖列中抽出,并从目标位置上掉落(直到不悬空,参见下面图1 和图2);



2、任一时刻,如果在一横行或者竖列上有连续三个或者三个以上相同颜色的方块,则它们将立即被消除(参见图1 到图3)。

注意:

a) 如果同时有多组方块满足消除条件,几组方块会同时被消除(例如下面图4,三个颜色为11 的方块和三个颜色为22 的方块会同时被消除,最后剩下一个颜色为22 的方块)。

b) 当出现行和列都满足消除条件且行列共享某个方块时,行和列上满足消除条件的所有方块会被同时消除(例如下面图5 所示的情形,55 个方块会同时被消除)。



3、方块消除之后,消除位置之上的方块将掉落,掉落后可能会引起新的方块消除。注意:掉落的过程中将不会有方块的消除。

上面图 1 到图3 给出了在棋盘上移动一块方块之后棋盘的变化。棋盘的左下角方块的坐标为(0,00,0),将位于(3,33,3)的方块向左移动之后,游戏界面从图1 变成图2 所示的状态,此时在一竖列上有连续三块颜色为44 的方块,满足消除条件,消除连续33 块颜色为44 的方块后,上方的颜色为3 的方块掉落,形成图3 所示的局面。

【输入】
共66 行。

第一行为一个正整数 nn,表示要求游戏通关的步数。

接下来的 55 行,描述7×57×5 的游戏界面。每行若干个整数,每两个整数之间用一个空格隔开,每行以一个00 结束,自下向上表示每竖列方块的颜色编号(颜色不多于1010 种,从11 开始顺序编号,相同数字表示相同颜色)。

输入数据保证初始棋盘中没有可以消除的方块。

【输出】
如果有解决方案,输出nn 行,每行包含33 个整数x,y,gx,y,g,表示一次移动,每两个整数之间用一个空格隔开,其中(x,yx,y)表示要移动的方块的坐标,gg 表示移动的方向,11 表示向右移动,−1−1 表示向左移动。注意:多组解时,按照xx 为第一关健字,yy 为第二关健字,11优先于−1−1,给出一组字典序最小的解。游戏界面左下角的坐标为(0,00,0)。

如果没有解决方案,输出一行,包含一个整数−1−1。

【输入样例】
3
1 0
2 1 0
2 3 4 0
3 1 0
2 4 3 4 0
【输出样例】
2 1 1
3 1 1
3 0 1
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int MAXN=10;

int n;
bool flag;
int g[MAXN][MAXN];

struct hehe{
    int x;
    int y;
    int p;
}ans[MAXN];

bool ok(int g[MAXN][MAXN]){
    for(int i=0;i<7;i++)
        for(int j=0;j<5;j++)
            if(g[i][j])
                return 0;
    return 1;
}

void fall(int g[MAXN][MAXN]){
    for(int j=0;j<5;j++)
        for(int i=0;i<7;i++)
            if(g[i][j]){
                int x=i;
                while(x>0&&!g[x-1][j]){
                    swap(g[x][j],g[x-1][j]);
                    x--;
                }
            }
}

bool xiao(int g[MAXN][MAXN]){
    int can=0;
    int G[MAXN][MAXN]={0};
    for(int i=0;i<7;i++){
        for(int j=0;j<5;j++){
            if(g[i][j]){
                if(j<3&&g[i][j]==g[i][j+1]&&g[i][j]==g[i][j+2]){
                    G[i][j]=1;
                    G[i][j+1]=1;
                    G[i][j+2]=1;
                }
                if(i<5&&g[i][j]==g[i+1][j]&&g[i][j]==g[i+2][j]){
                    G[i][j]=1;
                    G[i+1][j]=1;
                    G[i+2][j]=1;
                }
            }
        }
    }
    for(int i=0;i<7;i++){
        for(int j=0;j<5;j++){
            if(G[i][j]){
                g[i][j]=0;
                can=1;
            }
        }
    }
    return can;
}

void dfs(int t,int g[MAXN][MAXN]){
    if(t>n){
        if(ok(g)){
            flag=1;
            for(int i=1;i<=n;i++)
                cout<<ans[i].x<<" "<<ans[i].y<<" "<<ans[i].p<<endl;
        }
        return ;
    }

    int sum[MAXN];
    memset(sum,0,sizeof(sum));
    for(int i=0;i<7;i++)
        for(int j=0;j<5;j++)
            sum[g[i][j]]++;
    for(int i=1;i<10;i++)
        if(sum[i]==1||sum[i]==2)
            return ;

    int G[MAXN][MAXN];
    for(int j=0;j<4;j++){
        for(int i=0;i<7;i++){
            if(g[i][j]!=g[i][j+1]){
                for(int x=0;x<7;x++)
                    for(int y=0;y<5;y++)
                        G[x][y]=g[x][y];
                if(g[i][j]){
                    ans[t].x=j;
                    ans[t].y=i;
                    ans[t].p=1;
                }
                else{
                    ans[t].x=j+1;
                    ans[t].y=i;
                    ans[t].p=-1;
                }
                swap(G[i][j],G[i][j+1]);
                fall(G);
                while(xiao(G))
                    fall(G);
                dfs(t+1,G);
                if(flag)
                    return ;
            }
        }
    }
}


int main(){
//  freopen("mayan.in","r",stdin);
//  freopen("mayan.out","w",stdout);
    cin>>n;
    for(int j=0;j<5;j++){
        for(int i=0;;i++){
            scanf("%d",&g[i][j]);
            if(!g[i][j])
                break;
        }
    }
    dfs(1,g);
    if(!flag)
        cout<<-1;
    return 0;
}
1866:【11NOIP提高组】计算系数
给定一个多项式(ax+by)k(ax+by)k,请求出多项式展开后xnymxnym项的系数。

【输入】
共一行,包含 55 个整数,分别为a,b,k,n,ma,b,k,n,m,每两个整数之间用一个空格隔开。

【输出】
输出共11行,包含一个整数,表示所求的系数,这个系数可能很大,输出对1000710007取模后的结果。

【输入样例】
1 1 3 1 2
【输出样例】
3
#include<cstdio>
#include<cstring>
#include<algorithm>
#define p 10007
using namespace std;
int Power(int a,int b)
{
	int ans=1;
	for(;b;b>>=1,a=1ll*a*a%p)if(b&1)ans=1ll*ans*a%p;
	return ans;
}
int fac(int x)
{
	int i,ans=1;
	for(i=2;i<=x;++i)ans=ans*i%p;
	return ans;
}
int inv(int x)
{
	return Power(fac(x),p-2);
}
int main()
{
	int a,b,k,n,m;
	scanf("%d%d%d%d%d",&a,&b,&k,&n,&m);
	printf("%d\n",fac(k)*inv(n)%p*inv(k-n)%p*Power(a,n)%p*Power(b,m)%p);
	return 0;
}
1867:【11NOIP提高组】聪明的质监员
小TT是一名质量监督员,最近负责检验一批矿产的质量。这批矿产共有nn个矿石,从1到n 逐一编号,每个矿石都有自己的重量wiwi 以及价值vivi。检验矿产的流程是:

1、给定mm 个区间[Li,Ri][Li,Ri];

2、选出一个参数WW;

3、对于一个区间[Li,Ri][Li,Ri],计算矿石在这个区间上的检验值YiYi :

Yi=∑j1×∑jvj,j∈[Li,Ri]且wj≥W,j是矿石编号

这批矿产的检验结果Y 为各个区间的检验值之和。即:

Y=∑i=1mYi

若这批矿产的检验结果与所给标准值SS相差太多,就需要再去检验另一批矿产。小TT不想费时间去检验另一批矿产,所以他想通过调整参数WW 的值,让检验结果尽可能的靠近标准值SS,即使得S−YS−Y 的绝对值最小。请你帮忙求出这个最小值。

【输入】
第一行包含三个整数 n,m,Sn,m,S,分别表示矿石的个数、区间的个数和标准值。

接下来的 nn 行,每行22 个整数,中间用空格隔开,第i+1i+1 行表示ii 号矿石的重量wiwi 和价

值vivi 。

接下来的 mm 行,表示区间,每行22 个整数,中间用空格隔开,第i+n+1i+n+1 行表示区间[Li,Ri][Li,Ri]的两个端点LiLi 和RiRi。注意:不同区间可能重合或相互重叠。

【输出】
输出只有一行,包含一个整数,表示所求的最小值。

【输入样例】
5 3 15
1 5
2 5
3 5
4 5
5 5
1 5
2 4
3 3
【输出样例】
10
#include <bits/stdc++.h>
using namespace std;
const int SIZE=2000005;
const long long INF=0x3f3f3f3f3f3f3f3f;
#define ll long long
 
ll sum1[SIZE],sum2[SIZE],w[SIZE],v[SIZE],L[SIZE],R[SIZE];
ll Y,S,n,m,ans,mid,Left,Right;
 
bool check(int x)
{
	Y=0;
	memset(sum1,0,sizeof(sum1));
	memset(sum2,0,sizeof(sum2));
	for (int i=1;i<=n;i++){
		if (x<=w[i]){
			sum1[i]=sum1[i-1]+v[i];
			sum2[i]=sum2[i-1]+1;
		}
		else{
			sum1[i]=sum1[i-1];
			sum2[i]=sum2[i-1];
		}
	}
	
	for (int i=1;i<=m;i++){
		Y+=((sum1[R[i]]-sum1[L[i]-1])*(sum2[R[i]]-sum2[L[i]-1]));
	}
	if (Y>S) return true;
	else	 return false;
}
 
int main()
{
	scanf("%lld%lld%lld",&n,&m,&S);
	for (int i=1;i<=n;i++){
		scanf("%lld%lld",&w[i],&v[i]);
		Left=min(Left,w[i]);
		Right=max(Right,w[i]);
	}
	
	for (int i=1;i<=m;i++){
		scanf("%lld%lld",&L[i],&R[i]);
	}
	
	ans=INF;
	
	while (Left<=Right){
		mid=(Left+Right)/2;
		if (check(mid)) Left=mid+1;
		else			Right=mid-1;
		ans=min(ans,abs(Y-S)); 
	}
 
	printf("%lld\n",ans);
	
	return 0;
}
1868:【11NOIP提高组】观光公交

风景迷人的小城Y市,拥有nn个美丽的景点。由于慕名而来的游客越来越多,Y市特意安排了一辆观光公交车,为游客提供更便捷的交通服务。观光公交车在第0分钟出现在11号景点,随后依次前往2、3、4……n2、3、4……n 号景点。从第ii 号景点开到第i+1i+1 号景点需要DiDi 分钟。任意时刻,公交车只能往前开,或在景点处等待。

设共有mm个游客,每位游客需要乘车11次从一个景点到达另一个景点,第i位游客在TiTi分钟来到景点AiAi,希望乘车前往景点Bi(Ai<Bi)Bi(Ai<Bi)。为了使所有乘客都能顺利到达目的地,公交车在每站都必须等待需要从该景点出发的所有乘客都上车后才能出发开往下一景点。假设乘客上下车不需要时间。

一个乘客的旅行时间,等于他到达目的地的时刻减去他来到出发地的时刻。因为只有一辆观光车,有时候还要停下来等其他乘客,乘客们纷纷抱怨旅行时间太长了。于是聪明的司机ZZ 给公交车安装了kk 个氮气加速器,每使用一个加速器,可以使其中一个DiDi 减11。对于同一个DiDi 可以重复使用加速器,但是必须保证使用后DiDi 大于等于00。

那么 ZZ 该如何安排使用加速器,才能使所有乘客的旅行时间总和最小?

【输入】
第 11 行是33 个整数n,m,kn,m,k,每两个整数之间用一个空格隔开。分别表示景点数、乘客数和氮气加速器个数。

第 22 行是n−1n−1 个整数,每两个整数之间用一个空格隔开,第ii 个数表示从第ii 个景点开往第i+1i+1 个景点所需要的时间,即DiDi。

第 33 行至m+2m+2 行每行33 个整数Ti,Ai,BiTi,Ai,Bi,每两个整数之间用一个空格隔开。第i+2i+2 行表示第ii 位乘客来到出发景点的时,出发的景点编号和到达的景点编号。

【输出】
共一行,包含一个整数,表示最小的总旅行时间。

【输入样例】
3 3 2
1 4
0 1 3
1 1 2
5 2 3
【输出样例】
10
#include <bits/stdc++.h>
using namespace std;
 
const int Max=1005;
int n,m,k,ans,x;
int fa[Max*10],s[Max*10],t[Max*10],d[Max],f[Max],sum[Max],T[Max],last[Max];
//s起点t终点fa到达时间 
//d原时间i~i+1时间 
//f出发能影响到最远的点 
//sum前i个位置下车总人数 
//last在i上车的最大时间 
//T到i的最短时间 
 
inline void solve()
{
	for(int i=2;i<=n;i++) T[i]=max(T[i-1],last[i-1])+d[i-1];
	for(int i=2;i<=n;i++) sum[i]+=sum[i-1];
	for(int i=1;i<=m;i++) ans+=T[t[i]]-fa[i];
	while(k--)
	{
	  f[n]=f[n-1]=n;
	  for(int i=n-2;i>=1;i--)
	  {
	  	if(T[i+1]>last[i+1]) f[i]=f[i+1];
	  	else f[i]=i+1;
	  }
	  int maxx=0,pos=0;
	  for(int i=1;i<=n;i++) if(maxx<sum[f[i]]-sum[i]&&d[i]) maxx=sum[f[i]]-sum[i],pos=i;
	  if(!pos) break;
	  ans-=maxx,d[pos]--;
	  for(int i=pos;i<=n;i++) T[i]=max(T[i-1],last[i-1])+d[i-1];
	}
}
 
int main()
{
	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("%d%d%d",&fa[i],&s[i],&t[i]);
	  last[s[i]]=max(last[s[i]],fa[i]),sum[t[i]]++;
	}
	solve();
	cout<<ans;
	return 0;
}
1869:【12NOIP提高组】Vigenère密码
16 世纪法国外交家 Blaise de Vigenère 设计了一种多表密码加密算法——Vigenère 密码。Vigenère 密码的加密解密算法简单易用,且破译难度比较高,曾在美国南北战争中为南军所广泛使用。

在密码学中,我们称需要加密的信息为明文,用 MM 表示;称加密后的信息为密文,用CC 表示;而密钥是一种参数,是将明文转换为密文或将密文转换为明文的算法中输入的数据,记为 kk。 在 Vigenère 密码中,密钥 kk 是一个字母串,k=k1k2…knk=k1k2…kn。当明文 M=m1m2…mnM=m1m2…mn 时,得到的密文 C=c1c2…cnC=c1c2…cn,其中 ci=ci=m_i®k_i,运算,运算®$的规则如下表所示:



Vigenère 加密在操作时需要注意:

1. ®®运算忽略参与运算的字母的大小写,并保持字母在明文 MM 中的大小写形式;

2. 当明文 MM 的长度大于密钥 kk 的长度时,将密钥 kk 重复使用。

例如,明文 M=HelloworldM=Helloworld,密钥 k=abck=abc 时,密文 C=HfnlpyosndC=Hfnlpyosnd。



【输入】
输入共 22 行。

第一行为一个字符串,表示密钥 kk,长度不超过 100100,其中仅包含大小写字母。第二行为一个字符串,表示经加密后的密文,长度不超过 10001000,其中仅包含大小写字母。

【输出】
输出共 11 行,一个字符串,表示输入密钥和密文所对应的明文。

【输入样例】
CompleteVictory
Yvqgpxaimmklongnzfwpvxmniytm
【输出样例】
Wherethereisawillthereisaway
#include<bits/stdc++.h>
using namespace std;
char miyue[105], miwen[1005];
int main(){
	//初始化
	char ch[26][26]={'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
					'B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','A',
					'C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','A','B',
					'D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','A','B','C',
					'E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','A','B','C','D',
					'F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','A','B','C','D','E',
					'G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','A','B','C','D','E','F',
					'H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','A','B','C','D','E','F','G',
					'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','A','B','C','D','E','F','G','H',
					'J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','A','B','C','D','E','F','G','H','I',
					'K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','A','B','C','D','E','F','G','H','I','J',
					'L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','A','B','C','D','E','F','G','H','I','J','K',
					'M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','A','B','C','D','E','F','G','H','I','J','K','L',
					'N','O','P','Q','R','S','T','U','V','W','X','Y','Z','A','B','C','D','E','F','G','H','I','J','K','L','M',
					'O','P','Q','R','S','T','U','V','W','X','Y','Z','A','B','C','D','E','F','G','H','I','J','K','L','M','N',
					'P','Q','R','S','T','U','V','W','X','Y','Z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O',
					'Q','R','S','T','U','V','W','X','Y','Z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
					'R','S','T','U','V','W','X','Y','Z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q',
					'S','T','U','V','W','X','Y','Z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R',
					'T','U','V','W','X','Y','Z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S',
					'U','V','W','X','Y','Z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T',
					'V','W','X','Y','Z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U',
					'W','X','Y','Z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V',
					'X','Y','Z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W',
					'Y','Z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X',
					'Z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y',
					};
	cin >> miyue >> miwen;
	int len_miyue = strlen(miyue), len_miwen = strlen(miwen), i, j;
	for(i=0; i<len_miwen; ){//为了密钥的重复使用 
		for(j=0; j<len_miyue && i < len_miwen; ++j, ++i){
			char t_miwen = tolower(miwen[i]);//将密文转换为小写  便于比较 
			int hang = toupper(miyue[j]) - 65;//二维矩阵中的行 
			for(int k=0; k<26; ++k){//找到二维矩阵中对应的密文 
				char t_tmp = tolower(ch[hang][k]); 
				if(t_miwen == t_tmp){
					int t = islower(miwen[i])?97:65;
					cout << (char)(t+k);
					break;
				}
			}
		}
	}
	return 0;
}
 
 

1870:【12NOIP提高组】国王游戏
恰逢 H 国国庆,国王邀请 n 位大臣来玩一个有奖游戏。首先,他让每个大臣在左、右手上面分别写下一个整数,国王自己也在左、右手上各写一个整数。然后,让这 n 位大臣排成一排,国王站在队伍的最前面。排好队后,所有的大臣都会获得国王奖赏的若干金币,每位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右手上的数,然后向下取整得到的结果。

国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序,使得获得奖赏最多的大臣,所获奖赏尽可能的少。注意,国王的位置始终在队伍的最前面。

【输入】
第一行包含一个整数 n,表示大臣的人数。

第二行包含两个整数 a 和 b,之间用一个空格隔开,分别表示国王左手和右手上的整数。

接下来 n 行,每行包含两个整数 a 和 b,之间用一个空格隔开,分别表示每个大臣左手和右手上的整数。

【输出】
输出只有一行,包含一个整数,表示重新排列后的队伍中获奖赏最多的大臣所获得的金币数。

【输入样例】
3
1 1
2 3
7 4
4 6
【输出样例】
2
【提示】
【输入输出样例说明】

按 1、2、3 号大臣这样排列队伍,获得奖赏最多的大臣所获得金币数为 2;

按 1、3、2 这样排列队伍,获得奖赏最多的大臣所获得金币数为 2;

按 2、1、3 这样排列队伍,获得奖赏最多的大臣所获得金币数为 2;

按 2、3、1 这样排列队伍,获得奖赏最多的大臣所获得金币数为 9;

按 3、1、2 这样排列队伍,获得奖赏最多的大臣所获得金币数为 2;

按 3、2、1 这样排列队伍,获得奖赏最多的大臣所获得金币数为 9。

因此,奖赏最多的大臣最少获得 2 个金币,答案输出 2。

【数据范围】

对于 20%的数据,有 1≤ n≤ 10,0 < a、b < 8;

对于 40%的数据,有 1≤ n≤20,0 < a、b < 8;

对于 60%的数据,有 1≤ n≤100;

对于 60%的数据,保证答案不超过 109;

对于 100%的数据,有 1 ≤ n ≤1,000,0 < a、b < 10000。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
using namespace std;
typedef int arr[6005];
struct note{
    ll a,b,c;
}a[1005];
bool cmp(note x,note y) {
    return x.c<y.c;
}
int n,bz;
arr sum,ans,t;
char s[5];
void divv(int x){
    int yu=0;memset(t,0,sizeof(t));
    fd(i,sum[0],1) {
        yu=yu*10+sum[i];
        if (yu>=x) {
            if (!t[0]) t[0]=i;
            t[i]=yu/x;yu%=x;
        }
    }
}
void mx() {
    if (t[0]>ans[0]) memcpy(ans,t,sizeof(ans));
    else if (ans[0]==t[0]) {
        fd(i,ans[0],1) if (t[i]>ans[i]) {
            memcpy(ans,t,sizeof(ans));return;
        } else if (ans[i]<t[i]) return;
    }
}
void cheng(int x) {
    arr t;memset(t,0,sizeof(t));
    fo(i,1,sum[0]) {
        t[i]=t[i]+sum[i]*x;t[i+1]+=t[i]/10;t[i]%=10;
    }
    for(t[0]=sum[0];t[t[0]+1];) t[++t[0]+1]+=t[t[0]]/10,t[t[0]]%=10;
    memcpy(sum,t,sizeof(sum));
}
int main() {
    scanf("%d",&n);scanf("%s",s+1);
    fd(i,strlen(s+1),1) sum[++sum[0]]=s[i]-'0';scanf("%d",&bz);
    fo(i,1,n) scanf("%lld%lld",&a[i].a,&a[i].b),a[i].c=a[i].a*a[i].b;
    sort(a+1,a+n+1,cmp);
    fo(i,1,n) {
        divv(a[i].b);mx();cheng(a[i].a);
    }
    fd(i,ans[0],1) printf("%d",ans[i]);
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值