A:A. Points and Segments (easy)
題目看了n久,開始覺得尼瑪這是div2的題目麼,題目還標明瞭easy。。
意思是給你一n個點,m個區間,在n個點上放藍球或者紅球,然後讓你找一種選擇方案使得m個區間內的藍球和紅球數量之差不超過1.
開始想過用dfs,不過這只是div2的A題而已。。
然後想了下,直接輸出010101序列不就可以麼。
交了一發,發現要先排個序,再輸出就可以了。
AC程式碼:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int res[150];
struct node
{
int x,id;
}nod[150];
bool cmp(node a,node b)
{
return a.x<b.x;
}
int main()
{
int i,n,m;
int a,b;
while(~scanf("%d%d",&n,&m))
{
for(i=0;i<n;i++)
scanf("%d",&nod[i].x),nod[i].id=i;
for(i=0;i<m;i++)
scanf("%d%d",&a,&b);
sort(nod,nod+n,cmp);
int t=0;
for(i=0;i<n;i++)
res[nod[i].id]=(++t)%2;
printf("%d",res[0]);
for(i=1;i<n;i++)
printf(" %d",res[i]);
printf("\n");
}
return 0;
}
B:
B. Balls Game
題目大意:給你n個球,然後最多k個種類,同類的挨在一起同類的超過三個的可以抵消。開始的n個沒有抵消的情況,問給你一個顏色為x的球,問你用這個球insert進去最多能消掉n個球裡面的個數。
直接模擬就好,不過,自己被自己坑了好久。。
AC程式碼:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#define ll long long
using namespace std;
int a[105];
int main()
{
int n,k,x;
int i;
while(cin>>n>>k>>x)
{
int res=0;
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
for(i=1;i<=n;i++)
{
int ans=0,t1,t2;
if(a[i]==x&&i+1<=n&&a[i+1]==x)
{
ans+=2;
t1=i-1,t2=i+2;
while(t1>=1&&t2<=n)
{
int cnt=0;
int x=a[t1];
while(a[t2]==x&&t2<=n)
{
cnt++;
t2++;
}
while(a[t1]==x&&t1>=1)
{
cnt++;
t1--;
}
if(cnt<3) break;
else ans+=cnt;
}
res=max(res,ans);
}
}
cout<<res<<endl;
}
return 0;
}
/*
10 2 2
2 2 1 1 2 2 1 1 2 2
*/
題目大意:給你一顆樹,給你所有節點的初始狀態,然後再給你一個需要轉變到的狀態,如果一個節點的狀態發生改變,那麼他的兒子節點不變^0,他的兒子的兒子節點^1,他兒子的兒子的兒子。。找最小的次數。
直接從根,(題目說了根是1)往下dfs,即可。
AC程式碼:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=100005;
vector <int> mq[maxn];
int sta[maxn],en[maxn];
int res[maxn];
int cnt;
void dfs(int cur,int fa,int u,int v)
{
int flag=0;
sta[cur]^=v;
if(sta[cur]!=en[cur])
{
flag=1;
res[cnt++]=cur;
}
v=flag^v;
for(int i=0;i<mq[cur].size();i++)
{
int nex=mq[cur][i];
if(nex!=fa)
{
dfs(nex,cur,v,u);
}
}
}
int main()
{
int n,i;
while(cin>>n)
{
cnt=0;
int u,v;
for(i=1;i<=n;i++)
mq[i].clear();
for(i=1;i<n;i++)
{
cin>>u>>v;
mq[u].push_back(v);
mq[v].push_back(u);
}
for(i=1;i<=n;i++) cin>>sta[i];
for(i=1;i<=n;i++) cin>>en[i];
dfs(1,0,0,0);
cout<<cnt<<endl;
for(i=0;i<cnt;i++)
cout<<res[i]<<endl;
}
return 0;
}
/*
10
2 1
3 1
4 2
5 1
6 2
7 5
8 6
9 8
10 5
1 0 1 1 0 1 0 1 0 1
1 0 1 0 0 1 1 1 0 1
*/
D:D. Working out
題目大意:一個n*m的格子,一個人從(1,1)走到(n,m),一個人從(n,1)走到(1,m),他們速度不同,必須有一個交點,在那個交點那裡的分數不算,其他兩個人走過的格子分數都只算一次,問最大得多少分。第一個人只能往右下方向走,第二個人只能往右上方向走。
解題思路:我們需要列舉他們的交點,然後判定情況。需要記錄來的方向,dp,先四次dp預處理,然後找最大值。詳見圖片與程式碼。
可以思考下,只有這兩種情況,不然就會重疊,而重疊的只算一次的。
AC程式碼:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#define ll long long
using namespace std;
int dp[4][1005][1005];
int a[1005][1005];
int n,m;
void solve()
{
int i,j;
for(i=1; i<=n; i++) //左上
for(j=1; j<=m; j++)
dp[0][i][j] = max(dp[0][i-1][j],dp[0][i][j-1]) + a[i][j];
for(i=1; i<=n; i++) //右上
for(j=m; j>=1; j--)
dp[1][i][j] = max(dp[1][i-1][j],dp[1][i][j+1]) + a[i][j];
for(i=n; i>=1; i--) //左下
for(j=1; j<=m; j++)
dp[2][i][j] = max(dp[2][i][j-1],dp[2][i+1][j]) + a[i][j];
for(i=n; i>=1; i--) //右下
for(j=m;j>=1; j--)
dp[3][i][j] = max(dp[3][i][j+1],dp[3][i+1][j]) + a[i][j];
}
int main()
{
int i,j;
memset(dp,0,sizeof(dp));
while(cin>>n>>m)
{
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
scanf("%d",&a[i][j]);
solve();
int res = 0;
for(i=2; i<n; i++)
for(j=2; j<m; j++)
{
int t1,t2;
t1=dp[0][i-1][j]+dp[3][i+1][j]+dp[1][i][j+1]+dp[2][i][j-1];
t2=dp[0][i][j-1]+dp[3][i][j+1]+dp[1][i-1][j]+dp[2][i+1][j];
//cout<<t1<<" "<<t2<<endl;
res=max(res,max(t1,t2));
}
printf("%d\n",res);
}
return 0;
}
/*
3 3
100 100 100
100 1 100
100 100 100
*/
E題,DFS不知如何下手。