[原创]2014上海全国邀请赛 【(5+3)/10】

2017-07-23 20:46:34 Tabris_ 阅读数:422


博客爬取于2020-06-14 22:39:32
以下为正文

版权声明:本文为Tabris原创文章,未经博主允许不得私自转载。
https://blog.csdn.net/qq_33184171/article/details/75948179


日常血崩。
菜到爆了.

A HDU 5090 Game with Pearls

——————————————————————————————————————————
给你一个序列,可以把每个元素加上k的倍数或者不加, 问你最后能不能组成一个序列,第1个元素是1,第2个元素是2,第3个元素是3,。。


暴力模拟就行,从大小1的数开始,留下本身需要的1个,剩下的不断加K,知道当前的数没出现过。

最后扫一下判断就行


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# include <bits/stdc++.h>

using namespace std;

typedef long long int LL;

const int N = 1e5+7;

/******************************************************/

int a[N];
int vis[N];
int n,k;
int main(){
int _;
scanf("%d",&_);
while(_--){
memset(vis,0,sizeof(vis));
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
vis[a[i]]++;
}
int flag = 1;
for(int i=1;i<=n;i++){
for(int j=1;vis[i]>1;j++){
if(vis[j*k+i] == 0){
vis[j*k+i] = 1;
vis[i]--;
}
}
}

for(int i=1;i<=n;i++){
if(vis[i]!=1){
flag=0;
break;
}
}

if(flag) puts("Jerry");
else puts("Tom");
}
return 0;
}

B HDU 5091 Beam Cannon

——————————————————————————————————————————
在二维坐标系上给你一堆点,然后问你w*h这么大的矩形,最多能包含多少个点


用到了扫描线;

首先考虑一维的情况
如果是一维的,要统计长为w的线段最多能包括多少个位置怎么搞?

可以反过来考虑,然后变成一堆长w的线段覆盖,然后求的就是那个被覆盖最多的点,区间更新后求最大值就行了

而这个题
可以考虑将一个点变成一个矩形,
然后从左向右扫描

使扫描过程中,遇到矩形的左边就+1,右边就-1,

并维护一个线段树区间更新取最大值就好了


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# include <bits/stdc++.h>
typedef long long int LL;
using namespace std;

const int N = 1e6+7;
const int MOD = 1e9+7;

# define mp make_pair
# define pb push_back
# define yy1 second.first
# define yy2 second.second
# define vv first.second
/*********************************************/

vector<pair<pair<int,int>,pair<int,int> > >line;


int mx[N<<2],lazy[N<<2];

void pushdown(int rt){
if(lazy[rt]){
lazy[rt<<1 ]+=lazy[rt];
lazy[rt<<1|1]+=lazy[rt];
mx[rt<<1 ]+=lazy[rt];
mx[rt<<1|1]+=lazy[rt];
lazy[rt]=0;
}
}

void pushup(int rt){
mx[rt]=max(mx[rt<<1],mx[rt<<1|1]);
}

void update(int rt,int l,int r,int L,int R,int v){
if(L<=l&&r<=R){
lazy[rt]+=v;
mx[rt]+=v;
return ;
}
int m = r+l >> 1;
pushdown(rt);
if(L<=m) update(rt<<1 ,l ,m,L,R,v);
if(R> m) update(rt<<1|1,m+1,r,L,R,v);
pushup(rt);
}

int query(int rt,int l,int r,int L,int R){

}
int n,w,h;
int main(){
int _ = 1;
for(;scanf("%d",&n);){
if(n==-1) break;
scanf("%d%d",&w,&h);

memset(mx,0,sizeof(mx));
memset(lazy,0,sizeof(lazy));
line.clear();
for(int i=1,x,y;i<=n;i++){
scanf("%d%d",&x,&y);
line.pb(mp(mp(x , 1),mp(y,y+h)));
line.pb(mp(mp(x+w, 2),mp(y,y+h)));
}

sort(line.begin(),line.end());

int X = 90000;
int ans = 0;
for(int i=0;i<line.size();i++){
if(line[i].vv == 1){
update(1,1,X,line[i].yy1+20001,line[i].yy2+20001, 1);
ans = max(ans,mx[1]);
}
else {
ans = max(ans,mx[1]);
update(1,1,X,line[i].yy1+20001,line[i].yy2+20001,-1);
}

}
printf("%d\n",ans);
}
return 0;
}

C HDU 5092 Seam Carving

——————————————————————————————————————————
给你一个矩阵,让你找一个从上到下的路线,使得这个路线经过数的和最小,并且尽量靠右.

注意 a[i][j] 只能走到 a[i+1][j-1],a[i+1][j],a[i+1][j+1]


所以我们知道dp下到每个点的最小和,然后在最后一行找到最后一个最小的位置不算向回找就好了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# include <bits/stdc++.h>
typedef long long int LL;
using namespace std;

const int N = 1e6+7;
const int MOD = 1e9+7;

/*********************************************/

LL dp[111][111],a[111][111];
int ms[111],len,n,m;
int main(){
int _ = 1,kcase = 0;
for(scanf("%d",&_);_--;){
scanf("%d%d",&n,&m);

len = 0;
memset(dp,0,sizeof(dp));

for(int i=1;i<=n;i++){
a[i][0]= a[i][m+1]=10000000000000ll;
dp[i][0]=dp[i][m+1]=10000000000000ll;
for(int j=1;j<=m;j++)
scanf("%lld",&a[i][j]);
}

for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
dp[i][j]=a[i][j]+
min(dp[i-1][j-1],min(dp[i-1][j],dp[i-1][j+1]));
}
}

int p,mi = 10000000000000ll;;
for(int i=1;i<=m;i++){
if(dp[n][i]<=mi){
mi = dp[n][i];
p = i;
}
}

ms[++len] = p;
int tp;
for(int i=n-1;i;i--){
mi = dp[i][p-1];
tp = p-1;
if(mi>=dp[i][p]){
mi = dp[i][p];
tp = p;
}
if(mi>=dp[i][p+1]){
mi = dp[i][p+1];
tp = p+1;
}
p=tp;
ms[++len]=p;
}

printf("Case %d\n",++kcase);
for(int i=len;i;i--)
printf("%d%c",ms[i],(i==1)?'\n':' ');
}
return 0;
}

D HDU 5093 Battle ships

——————————————————————————————————————————
给你一个NM的图,其中’‘可以放传,但是注意同一行一列只能放一个船,除非被’#'隔开,问你最多能放几个船.


首先考虑每个行和列分开之后,没有被隔开的部分就是一个整体了,

然后考虑 ,处理完的这一个个, 行与列没有被隔开的中

假设行1 和列1,列2,列3, 没有被隔开,

那么行1只能找一个列对应的位置来放船,

然后这就是一个二分匹配模型了,、、

然后就用行与列建二分图求最大匹配就好了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# include<stdio.h>
# include<string.h>
# include<vector>
using namespace std;
vector<int>mp[25000+50];
int vis[25000+50];
int match[25000+50];
int find(int u){
// printf("%d %d\n",u,mp[u].size());
for(int i=0;i<mp[u].size();i++){
int v=mp[u][i];
if(vis[v]==0){
vis[v]=1;
if(match[v]==-1||find(match[v])){
match[v]=u;
return 1;
}
}
}
return 0;
}

int h[111][111],l[111][111];
char a[111][111];

int n,m;

void add(int u,int v){
// printf("%d %d< -\n",u,v);
mp[u].push_back(v);
}

void solve(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%s",a[i]+1);

int cnt = 0;
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
h[i][j]=l[i][j]=-1;

memset(h,-1,sizeof(h));
memset(l,-1,sizeof(l));

for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i][j]=='#') continue;
if(-1==h[i][j-1])h[i][j]=++cnt;
else h[i][j]=h[i][j-1];
}
}

for(int j=1;j<=m;j++){
for(int i=1;i<=n;i++){
if(a[i][j]=='#') continue;
if(-1==l[i-1][j])l[i][j]=++cnt;
else l[i][j]=l[i-1][j];
}
}

for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
if(a[i][j]=='*') add(h[i][j],l[i][j]);

for(int i=1;i<=cnt;i++) match[i]=-1;

int output=0;
for(int i=1;i<=cnt;i++){
for(int j=1;j<=cnt;j++) vis[j]=0;
if(find(i))output++;
}

printf("%d\n",output);
for(int i=1;i<=cnt;i++) mp[i].clear();
return ;
}

int main(){
int t;for(scanf("%d",&t);t--;) solve();
}

E HDU 5094 Maze

——————————————————————————————————————————
给你一个图,


二进制枚举状态搜索,

队友A的,待补

-----------------------Update-----------------------------

就是搜索么。
我用a[x][y][0~3] 记录每个位置4个方向的们需要那种钥匙开 用a[x][y][4]记录(x,y)这个位置的钥匙是那种,

因为又9种钥匙, 所以只要用一个9位的二进制数进行枚举就好了

用vis[x][y][1<<10] 来标记每种状态下走到(x,y)、、

然后直接搜索就好了

注意不能走到输出-1;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# include <bits/stdc++.h>

typedef long long int LL;
using namespace std;

# define abs(x) ((x)>0?(x):-(x))
# define rep(a,b,c) for(int a=(b),end=(c);a<=end;a++)

const int N = 2000+7;
const int MOD = 1e9+7;

/******************************************************/

int n,m,q,k;
int a[55][55][10];
bool vis[55][55][1<<11];
int fx[]={0,0,1,-1};
int fy[]={1,-1,0,0};

struct node {
int x,y,step,s;
};

int bfs(int x,int y){
queue<node>q;
node tmp,tem;
tmp.x = x,tmp.y = y;
tmp.step = 0,tmp.s = 0;
q.push(tmp);
vis[1][1][0]=1;
int xx,yy,ss,st;
while(!q.empty()){
tem = q.front();q.pop();
if(tem.x == n&&tem.y == m)
return tem.step;

for(int i=0;i<4;i++){
if( a[tem.x][tem.y][i]==-1) continue;
if((a[tem.x][tem.y][i]&tem.s) != a[tem.x][tem.y][i]) continue;
xx = tem.x + fx[i];
yy = tem.y + fy[i];
ss = (tem.s | a[xx][yy][4]);
st = tem.step + 1;
if(xx<1||xx>n) continue;
if(yy<1||yy>m) continue;
if(vis[xx][yy][ss]) continue;
vis[xx][yy][ss]=1;
tmp.x = xx;
tmp.y = yy;
tmp.s = ss;
tmp.step = st;
q.push(tmp);
}
}
return -1;
}


int main(){
while(~scanf("%d%d%d",&n,&m,&q)){
memset(vis,0,sizeof(vis));
memset(a ,0,sizeof(a ));

scanf("%d",&k);
for(int i=1,f,x1,x2,y1,y2,p;i<=k;i++){
scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&p);
if(p == 0) f=-1;
else f=1<<(p-1);
for(int j=0;j<4;j++){
if(x1+fx[j]==x2&&y1+fy[j]==y2){
a[x1][y1][j]|=f;
break;
}
}
for(int j=0;j<4;j++){
if(x2+fx[j]==x1&&y2+fy[j]==y1){
a[x2][y2][j]|=f;
break;
}
}
}

scanf("%d",&k);
for(int i=1,x1,y1,p;i<=k;i++){
scanf("%d%d%d",&x1,&y1,&p);
a[x1][y1][4]|=1<<(p-1);
}

printf("%d\n",bfs(1,1));
}
return 0;
}

F HDU 5095 Linearization of the kernel functions in SVM

——————————————————————————————————————————
给你10个系数,让你把10项的多项式的最简形式表示出来,


小模拟

注意开始的数是正数的时候没有正号,
系数为1 的要省略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# include <bits/stdc++.h>

using namespace std;

typedef long long int LL;

const int N = 1e5+7;

/******************************************************/

int a[N];
char ch[100]={' ','p','q','r','u','v','w','x','y','z'};
int n,k;
int main(){
int _; scanf("%d",&_);
while(_--){
for(int i=1;i<=10;i++) scanf("%d",&a[i]);

int i;
for(i=1;i<=10;i++) if(a[i]!=0) break;

int flag=0;

for(;i<10;i++){
if(a[i]==0) continue;
if(a[i]<0) {flag=1;
if(a[i]==-1) printf("-%c",ch[i]);
else printf("%d%c",a[i],ch[i]);
}
else {
if(flag) printf("+");flag=1;
if(a[i]!=1) printf("%d%c",a[i],ch[i]);
else printf("%c",ch[i]);
}
}

if(a[10]!=0) {
if(a[10]>0) {
if(flag) printf("+");flag=1;
printf("%d",a[10]);
}
else {
printf("%d",a[10]),flag=1;
}
}
if(flag == 0) printf("0");
puts("");

}
return 0;
}
/***
5555
0 0 0 0 0 0 0 0 0 0
-5 -2 5 5 5 5 5 5 5 5
0 46 3 4 -5 -22 -8 -32 24 27
2 31 -5 0 0 12 0 0 -49 12
-1 -1 -1 0 0 4 0 0 -6 7
0 0 0 0 0 -5 0 0 0 0
1 1 1 1 1 1 1 1 1 1
-1 -1 -1 -1 -1 -1 -1 -1 -1
-1 1 -1 1 -1 1 -1 1 -1 1
1 -1 1 -1 1 -1 1 -1 1 -1

*/

G HDU 5096 ACM Rank

——————————————————————————————————————————

大模拟,不补.

H HDU 5097 Page Rank

——————————————————————————————————————————
待补…


I HDU 5098 Smart Software Installer

——————————————————————————————————————————
给你一堆程序,后面带’*‘好的需要重启之后才能生效,’:’ 后面的是需要安装完这个程序,才能开始安装的程序

问你最少需要打印多少次


题目很水,就是题面太长了。没读。。。

只要注意到要把当前需要重启的程序个数最大化就好了。

过程就是个拓扑,

然后就是如何处理这个恶心的读入了。。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# include <bits/stdc++.h>
typedef long long int LL;
using namespace std;

const int N = 1e6+7;
const int MOD = 1e9+7;

# define pb push_back

/*********************************************/

int deg[N];
bool vis[N];
int cnt;
int ms[N],len;
int ms2[N],len2;

string s;char t[N];
vector<int >G[N];

void add(int u,int v){
G[u].pb(v);
deg[v]++;
}

map<string ,int >mp;

void topo(){
queue<int >q;
while(len) q.push(ms[len--]);

while(!q.empty()){// puts("++");
int u = q.front();q.pop();
// printf("cnt = %d : %d\n",cnt,u);
for(int i=0;i<G[u].size();i++){
int to = G[u][i];
deg[to]--;
if(deg[to] == 0){
if(vis[to]) ms[++len] = to;
else q.push(to);//,printf("%d <--\n",to);
}
}
}
}

void solve(){
len = len2 = 0;

for(int i=1;i<=cnt;i++)
if(deg[i]==0){
if(vis[i]) ms2[++len2]=i;
else ms[++len ]=i;
}
// printf("<%d,%d>\n",len,len2);
int ans = 0;
for(;len||len2;){ans++;
topo();
while(len2) ms[++len] = ms2[len2--];
}
printf("%d\n",ans-1);

for(int i=1;i<=cnt;i++) G[i].clear(),vis[i]=deg[i]=0;
return ;
}

void init(){
mp.clear();cnt=0;

int flag;
string id1,id2;
while(getline(cin,s) != NULL){
if(s[0] == '\0') break;
istringstream sin(s);
sin >> t;
flag = 0;
int len = strlen(t);
for(int i = 0; i < len; ++i)
if(t[i] == '*') flag = 1;
t[len - 1 - flag] = '\0';
id1 = t;
if(mp[id1] == 0) mp[id1]= ++cnt;
vis[mp[id1]] = flag;
while(sin >> id2){
if(mp[id2] == 0)
mp[id2] = ++cnt;
add(mp[id2],mp[id1]);
}
}

return ;
}

int main(){
int _ = 1,kcase = 0;
cin>>_;
getchar();
getchar();
for(;_--;){
init();
// for(int i=1;i<=cnt;i++){
// printf("%d: ",i);
// for(int j=0;j<G[i].size();j++){
// printf(" %d-%d*",G[i][j],deg[G[i][j]]);
// }
// puts("");
// }
// for(int i=1;i<=cnt;i++) printf("deg[%d]=%d\n",i,deg[i]);

printf("Case %d: ",++kcase);
solve();
}
return 0;
}

J HDU 5099 Comparison of Android versions

——————————————————————————————————————————

给你两个字符串,然后按照规则比较下大小.


我做傻逼了

队友A的

题傻逼不补

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# include <bits/stdc++.h>
using namespace std;
char a[1500];
char b[1500];
# define mme(i,j) memset(i,j,sizeof(i))
void print(int vala ,int valb )
{
if(vala>valb)printf(">");
else if(vala==valb)printf("=");
else printf("<");
}

int opt[3];
int main()
{
int t;
int kase=0;
scanf("%d",&t);
while(t--)
{
mme(opt,0);
scanf("%s%s",a+1,b+1);
printf("Case %d: ",++kase);
if(a[1]==b[1])//0--->= 1----> -1----<
opt[1]=0;
else if(a[1]>b[1])
opt[1]=1;
else opt[1]=-1;

if(a[2]!=b[2])// bu tong
{
if(a[3]==b[3])
{
if(a[4]==b[4])
{
if(a[5]==b[5])
opt[2]=0;
else{
if(a[5]>b[5])
opt[2]=1;
else
opt[2]=-1;
}
}else {
if(a[4]>b[4])
opt[2]=1;
else opt[2]=-1;
}
}else {
if(a[3]>b[3])
opt[2]=1;
else
opt[2]=-1;
}
}else {
if(strcmp(a+3,b+3)>0)
opt[2]=1;
else if(strcmp(a+3,b+3)<0)
opt[2]=-1;
else opt[2]=0;
}
if(opt[1]==1)
printf("> ");
else if(opt[1]==-1)
printf("< ");
else printf("= ");

if(opt[2]==1)
printf(">\n");
else if(opt[2]==-1)
printf("<\n");
else printf("=\n");
}
}