问题描述:
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
−
>
1110
1111->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]);
}