20181025模拟赛(小贪心+小模拟+大暴力+神奇建边)

问题描述:
CZYZ校园内有一家打印店,收费有着奇葩的规则,对于打印的量不同的情况会收取不同的费用。例如打印少于100张的时候,收取20分每张,但是打印不少于100张,收取10分每张,显然打印99张时候应该打印100张,而不是打印99张。现在告诉你打印店的收费策略,给出一些询问,求出打印若干张时候最少需要支付的钱数。

问题输入:
输入数据包含三行,第一行包含两个数n和m,表示打印策略的种类有n种,询问有m个;
接下来一行有2n个整数,即S1,P1,S2,P2…Sn,Pn,表示当打印数量不少于Si时,每张收取Pi分。
第三行包含m个整数Q1,Q2,Q3…Qm,表示询问打印Qi张时,最少花多少钱(分)。

问题输出:
对于每个询问,输出一行一个整数,表示最少花多少分钱打印Qi张。

Sample 1
Input
2 3
0 20 100 10
0 99 100
Output
0
1000
1000
问题描述:
这是另一道处理合法括号序列的题目。
我们应该提醒你,如果一个括号序列插入“+”和“1”后,可以得到一个正确的数学表达式,那么它被称为“合法”的。
例如,序列“(())()”,“()”和“(()(()))”是合法的,但“)(”,“(()”
和“(()))(”不是。
给出一个由“(”和“)”字符组成的字符串。你要找出它最长的是合法括号序列的子串,也同样要找出最长子串的个数。

问题输入:
一行包含一个非空字符串,由“(”和“)”字符组成,长度不超过10^6。

问题输出:
输出最长合法括号序列的子串的长度,和最长子串的个数。
如果不存在这种子串,输出唯一的一行,包含“0 1”。

Sample 1
Input
)((())))(()())
Output
6 2
Sample 2
Input
))(
Output
0 1
数据规模:
对于50%的数据满足:读入的字符串长度小于等于1000;
对于100%的数据满足:读入的字符串长度小于等于1000000。
问题描述:
一个M行N列的棋盘,里面放了M * N个各种颜色的钻石。每一次你可以选择任意两个相邻的颜色不同的钻石,进行交换。两个格子相邻的定义是两个格子有一条公共边。每次交换的分值为通过这次交换后能够形成的最大矩形的面积,具体请见样例。
跟传统的钻石游戏不太一样的是,交换后钻石不会消除。现在告诉你每一次操作,请输出每一次所能得到的分值。

问题输入:
第一行二个整数M,N。
接下来M行N列,表示第I行第J列的钻石的颜色(1~9)。
第M+2行有一个正整数P,表示钻石交换的次数。
接下来P行,每行四个正整数x1,y1,x2,y2,1<=x1,x2<=M,1<=y1,y2<=N,表示交换(x1,y1)和(x2,y2)的钻石。
保证(x1,y1),(x2,y2)的颜色不相同,并且其必定相邻。

问题输出:
P行,输出每次交换得到的分值。

Sample 1
Input
4 5
1 1 1 3 4
1 1 2 1 2
1 1 1 2 2
3 3 3 4 4
2
2 3 2 4
1 4 1 5
Output
9
1
【样例解释】

Limitation
1s, 256MiB for each test case.
数据限制:
40%的数据,M,N <= 50,P <= 1000;
100%的数据,M,N <= 500,P <= 1000。
Problem C. Walk(walk.c/cpp/pas)
Input file: walk.in
Output file: walk.out
Time limit: 1 seconds
Memory limit: 128 megabytes
在比特镇一共有n 个街区,编号依次为1 到n,它们之间通过若干条单向道路连接。
比特镇的交通系统极具特色,除了m 条单向道路之外,每个街区还有一个编码vali,不同街区可能
拥有相同的编码。如果vali and valj = valj,即vali 在二进制下与valj 做与运算等于valj,那么也会
存在一条额外的从i 出发到j 的单向道路。
Byteasar 现在位于1 号街区,他想知道通过这些道路到达每一个街区最少需要多少时间。因为比特
镇的交通十分发达,你可以认为通过每条道路都只需要1 单位时间。
Input
第一行包含两个正整数n;m,表示街区的总数以及道路的总数。
第二行包含n 个正整数val1; val2; :::; valn,分别表示每个街区的编码。
接下来m 行,每行包含两个正整数ui; vi,表示一条单向道路,起点为ui,终点为vi。
Output
输出n 行,每行一个整数,其中第i 行输出到达第i 个街区的最少时间,如果无法到达则输出?1。

只有聪明人才能看得懂题面

T1
题意概括:每个时刻对应的打印稿价格不同,求打印一份打印稿要多少时间

(因为价格不同,所以可以取大的),所以小贪心

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int n,m;
long long s[maxn],p[maxn],prmin[maxn],pr[maxn];
int main()
{
	//freopen("printer.in","r",stdin);
	//freopen("printer.out","w",stdout);
	scanf("%d%d",&n,&m);
	for (int i=1; i<=n; i++)
	  {
	  	scanf("%d%d",&s[i],&p[i]);
	  	pr[i]=s[i]*p[i];
	  	//cout<<pr[i]<<' '; 
	  }
	//cout<<endl;
	long long ans=9999999999999999; 
	for (int i=n; i>=1; i--)
	  {
	  	prmin[i]=min(ans,pr[i]);
	  	ans=prmin[i];
	  }
	while (m--)
	  {
	  	int x;
	  	scanf("%d",&x);
	  	int posx=lower_bound(s+1,s+n+1,x)-s;
	  	long long numx=0,numy=99999999999999;
	  	if (s[posx]==x) numx=x*p[posx]; else numx=x*p[posx-1];
	  	if (prmin[posx]!=0) numy=prmin[posx];
	  	//cout<<posx<<' '<<numx<<' '<<numy<<endl;
	    printf("%lld\n",min(numy,numx));
      }
}

T2
提议概括:求最长合法括号子序列及最长方案数

分别用左括号,右括号去匹配(右括号,左括号),比原来长就更新,跟原来一样则方案数++
注意不能单向做:单向做的话,((),按照我的思路,就没有停止出解了。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1000010;
string s;
int n,m;
int main()
{
	cin>>s;
	int len=s.size()-1;
	int i=0,j=0,numl=0,numr=0,ansnum=0,ans=0;
	while (i<=len&&j<=len)
	  {
	     if (s[j]=='(') numl++; else numr++;
	     j++;
		 if (numl==numr) 
		   {
		   	  int num=min(numl,numr)*2;
		      if (ans==num&&ans!=0) ansnum++;
		      if (num>ans)
		        {
		        	ans=num;
		        	ansnum=1;
		        }
		   }
		if (numl<numr) {numl=numr=0; i=j;}
	  }
	if (ansnum==0) ansnum=1;
	i=len,j=len,numl=0,numr=0;
	int ansnum2=0,ans2=0;
	while (i>=0&&j>=0)
	  {
	     if (s[j]==')') numr++; else numl++;
	     j--;
		 if (numl==numr) 
		   {
		   	  int num=min(numl,numr)*2;
		      if (ans2==num&&ans2!=0) ansnum2++;
		      if (num>ans2)
		        {
		        	ans2=num;
		        	ansnum2=1;
		        }
		   }
		if (numl>numr) {numl=numr=0; i=j;}
	  }
	if (ansnum2==0) ansnum2=1;
	if (ans==ans2) printf("%d %d",ans,max(ansnum,ansnum2));
    else 
	if (ans>ans2) printf("%d %d",ans,ansnum);
	else printf("%d %d",ans2,ansnum2);
}

T3
题意概括:每回更换两个相邻元素,求最大相同元素子矩阵

……暴力,记点,从四个方向暴力找,先找边,再匹配矩阵,其实很快。

#include<stdio.h>
#include<bits/stdc++.h>
using namespace std;

int n,m,g[505][505],Q;

int cont(int x,int y,int p){
	int ls1=199999999,ls2=199999999,ans=0;
	int c=g[x][y];
	if(p==1){
		for(int i=x;i>=1&&g[i][y]==c;i--)
		{
			int j;
			for(j=y;j>=1&&y-j<=ls1&&g[i][j]==c;j--) ;
			j++;
			ls1=min(ls1,y-j);
			for(j=y;j<=m&&j-y<=ls2&&g[i][j]==c;j++) ;
			j--;
			ls2=min(ls2,j-y);
			ans=max((x-i+1)*(ls1+ls2+1),ans);
		}
	}else if(p==3){
		for(int i=x;i<=n&&g[i][y]==c;i++)
		{
			int j;
			for(j=y;j>=1&&y-j<=ls1&&g[i][j]==c;j--) ;
			j++;
			ls1=min(ls1,y-j);
			for(j=y;j<=m&&j-y<=ls2&&g[i][j]==c;j++) ;
			j--;
			ls2=min(ls2,j-y);
			ans=max((i-x+1)*(ls1+ls2+1),ans);
		}
	}else if(p==4){
		for(int j=y;j>=1&&g[x][j]==c;j--)
		{
			int i;
			for(i=x;i>=1&&x-i<=ls1&&g[i][j]==c;i--) ;
			i++;
			ls1=min(ls1,x-i);
			for(i=x;i<=n&&i-x<=ls2&&g[i][j]==c;i++) ;
			i--;
			ls2=min(ls2,i-x);
			ans=max((y-j+1)*(ls1+ls2+1),ans);
		}	
	}else{
		for(int j=y;j<=m&&g[x][j]==c;j++)
		{
			int i;
			for(i=x;i>=1&&x-i<=ls1&&g[i][j]==c;i--) ;
			i++;
			ls1=min(ls1,x-i);
			for(i=x;i<=n&&i-x<=ls2&&g[i][j]==c;i++) ;
			i--;
			ls2=min(ls2,i-x);
			ans=max((j-y+1)*(ls1+ls2+1),ans);
		}
	}
	return ans;
} 

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			scanf("%d",&g[i][j]);
	scanf("%d",&Q);
	int xx,x2,yy,y2;
	while (Q--)
	{
		scanf("%d%d%d%d",&xx,&yy,&x2,&y2);
		swap(g[xx][yy],g[x2][y2]);
		if(xx<x2){
			printf("%d\n",max(cont(xx,yy,1),cont(x2,y2,3)));
		}else if(xx>x2){
			printf("%d\n",max(cont(xx,yy,3),cont(x2,y2,1)));
		}else{
			if(yy<y2){
				printf("%d\n",max(cont(xx,yy,4),cont(x2,y2,2)));
			}else{
				printf("%d\n",max(cont(xx,yy,2),cont(x2,y2,4)));
			}
		} 
	}
}

T4:
题意概括:
有一张图,除了本身连的边,还要将 v a l i a n d v a l j = v a l j vali and valj = valj valiandvalj=valj相同的边,求每组方案的最短路

因为我们不能枚举判定,也不能直接相连,所以需要考虑转化。
考虑新增 2 2 0 2^20 220 个点,这些点中 i i i 向它所有位 1 1 1的位置去掉这个 1 1 1的影响的点连一条边权为 0 0 0的有向边.
例如 1111 − &gt; 1110 1111-&gt;1110 1111>1110,我们可以通过走多条这种有向边的方式到达他的所有子集点,即KaTeX parse error: Expected 'EOF', got '&' at position 2: i&̲j=i的点。
对于原来的 n n n 个点,先把 m m m 条边连好,连权值为 1 1 1的有向边,然后对于 i 号点,由它向新增的第 v a l i vali vali个点(就是他权值所对应的点)连一条权值为 1 1 1 的有向边,再由新增的第 v a l i vali vali 个点向它连一条权值为 0 0 0 的有向边。
BFS 的时候,每次要把用 0 0 0权值的边连接的所有点都加入队尾,以保证距离不降

#include<bits/stdc++.h>
using namespace std;
const int maxn=2000010;
int n,m,dis[maxn],cnt;
int head[maxn],nxt[maxn],head0[maxn],v[maxn],tot;
queue<int> p;
void add(int u,int y)
{
	cnt++; 
	nxt[cnt]=head[u]; 
	head[u]=cnt; 
	v[cnt]=y;
}
void add1(int u,int y)
{
	cnt++; 
	nxt[cnt]=head0[u]; 
	head0[u]=cnt; 
	v[cnt]=y;
}
void dfs(int x,int len)
{
	if (dis[x]>=0) return;
	p.push(x);
	dis[x]=len;
	for (int i=head0[x];i;i=nxt[i])
	 dfs(v[i],len);
	if (x>=tot) return;
	for (int i=0;i<20;i++)
	 if (x>>i&1)
	  dfs(x^(1<<i),len);
}
int main()
{
	scanf("%d%d",&n,&m);
	tot=1<<20;
	for (int i=1;i<=n;i++)
      {
		int x; 
		scanf("%d",&x);
		add(tot+i,x);
		add1(x,tot+i);
	  }
	for (int i=1;i<=m;i++)
	 {
	 	int x,y; 
		 scanf("%d%d",&x,&y);
	 	add(tot+x,tot+y);
	 }
	for (int i=0;i<=tot+n;i++) dis[i]=-1;
	dfs(tot+1,0);
	while (!p.empty())
	  {
		int now=p.front(); 
		p.pop();
		for (int i=head[now];i;i=nxt[i])
		 dfs(v[i],dis[now]+1);
	  } 
	for (int i=1;i<=n;i++)
	  printf("%d\n",dis[tot+i]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值