又是一次gdkoi的學校選拔的比賽。
傷心透了。 滿分:400 分數:132
題目如下:
<span style="font-family:Microsoft YaHei;font-size:14px;">中位數
【題目描述】
給出1~n的一個排列,統計該排列有多少個長度爲奇數的連續子序列的中位數是b。中位數是指把所有元素從小到大排列後,位於中間的數。
【輸入格式】
第一行爲兩個正整數n和b ,第二行爲1~n 的排列。
【輸出格式】
輸出一個整數,即中位數爲b的連續子序列個數。
【樣例】
輸入 輸出
5 4
1 2 3 4 5 2
6 3
1 2 4 5 6 3 1
7 4
5 7 2 4 3 1 6 4
第三個樣例解釋:{4}, {7,2,4}, {5,7,2,4,3}和{5,7,2,4,3,1,6}。
【數據規模】
編號 1 2 3 4 5 6 7 8 9 10
N 10 50 100 300 1000 3600 10000 25000 55555 100000</span>
對於這道題,先打了個暴力,再是打了個優化往兩邊搜,但是還是果斷超時了幾個點
其實這道題就是向左連續的找,話很難說明把,直接打比方
例如第三個樣例
左邊就是 1 0 -1 0 大就加,小就減
所以數組就是 {...1,2,1} 就是記錄個數
之後右邊找找 0,-1,-2,-1
結果發現 右邊的-1對應 左邊的1
右邊的0對應 左邊的0
所以就是1+1+2=4。
具體爲什麼,想想就知道啦。
Code:
<span style="font-family:SimSun;font-size:10px;">#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int n,b,a[110000],p;
void Input()
{
scanf("%d%d",&n,&b);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(a[i]==b) p=i;
}
}
int fl[210000],fr[210000];
int ans=0;
void Solve()
{
int w=0;
for(int i=p;i>=1;i--)
{
if(a[i]>a[p]) w--;
if(a[i]<a[p]) w++;
fl[w+p]++;
}
w=0;
for(int i=p;i<=n;i++)
{
if(a[i]>a[p]) w++;
if(a[i]<a[p]) w--;
fr[w+p]++;
}
for(int i=1;i<=n;i++)
ans+=fr[i]*fl[i];
}
void Output()
{
printf("%d\n",ans);
}
int main()
{
freopen("median.in","r",stdin);
freopen("median.out","w",stdout);
Input();
Solve();
Output();
return 0;
}</span><span style="font-family:Microsoft YaHei;font-size:14px;">
</span>
<span style="font-family:Microsoft YaHei;font-size:14px;">葉子的顏色
【題目描述】
給一棵m個結點的無根樹,你可以選擇一個度數大於1的結點作爲根,然後給一些結點(根、內部結點和葉子均可)着以黑色或白色。你的着色方案應該保證根結點到每個葉子的簡單路徑上都至少包含一個有色結點(哪怕是這個葉子本身)。
對於每個葉結點u,定義c[u]爲從u到根結點的簡單路徑上第一個有色結點的顏色。給出每個c[u]的值,設計着色方案,使得着色結點的個數儘量少。
【輸入格式】
第一行包含兩個正整數m, n,其中n是葉子的個數,m是結點總數。結點編號爲1,2,…,m,其中編號1,2,… ,n是葉子。以下n行每行一個0或1的整數(0表示黑色,1表示白色),依次爲c[1],c[2],…,c[n]。以下m-1行每行兩個整數a,b(1<=a < b <= m),表示結點a和b 有邊相連。
【輸出格式】
僅一個數,即着色結點數的最小值。
【樣例】
輸入 輸出
5 3
0
1
0
1 4
2 5
4 5
3 5 2
【數據規模】
數據 1 2 3 4 5 6 7 8 9 10
m 10 50 100 200 400 1000 4000 8000 10000 10000
n 5 23 50 98 197 498 2044 4004 5021 4996
</span>
這道題在考場上,連題目都沒看。
題目現在我也不講了,你們看看把。
解法就是tree dp
首先就是b數組的定義。
b[0]就是我的孩子和孫子等等有多少個需要我變爲0的。
b[1]同上。
b[2]就是我的孩子是中間派的,就是變0和變1都很隨和的。
s就是我的孩子的總數
<span style="font-family:SimSun;font-size:10px;">if(b[0]>b[1]) {col[x]=0; s=s-b[0]-b[2]+1;}
else if(b[1]>b[0]) {col[x]=1; s=s-b[1]-b[2]+1;}
else {col[x]=2; s=s-b[1]-b[2]+1;}</span>
很好理解吧其實,col[]就是我變成什麼顏色咯。
就下來我都不多羅嗦了,直接遞歸尋找s咯
Code:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m;
int col[110000];
struct node
{
int x,y,next;
}a[210000]; int len,first[110000];
void ins(int x,int y)
{
len++; a[len].x=x; a[len].y=y;
a[len].next=first[x]; first[x]=len;
}
void Input()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d",&col[i]);
len=0; memset(first,0,sizeof(first));
for(int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
ins(x,y); ins(y,x);
}
}
int ans;
int Tree_Dp(int x,int fa)
{
if(x<=m) return 1;
int b[3]; memset(b,0,sizeof(b));
int s=0;
for(int k=first[x];k;k=a[k].next)
{
int y=a[k].y;
if(y!=fa)
{
int t=Tree_Dp(y,x);
s+=t;
b[col[y]]++;
}
}
if(b[0]>b[1]) {col[x]=0; s=s-b[0]-b[2]+1;}
else if(b[1]>b[0]) {col[x]=1; s=s-b[1]-b[2]+1;}
else {col[x]=2; s=s-b[1]-b[2]+1;}
return s;
}
void Solve()
{
int sum; ans=m+1;
sum=Tree_Dp(n,0);
ans=min(ans,sum);
}
void Output()
{
printf("%d\n",ans);
}
int main()
{
freopen("color.in","r",stdin);
freopen("color.out","w",stdout);
Input();
Solve();
Output();
return 0;
}
<span style="font-family:Microsoft YaHei;font-size:14px;">循環賽
【題目描述】
n支隊伍打比賽,每兩支隊伍恰好比賽一場。平局時各得1分,而有勝負時勝者3分,負者0分。
假設三支隊伍得分分別爲3, 3, 3,則可能有兩種情況:
隊伍 A B C 得分
A - 3 0 3
B 0 - 3 3
C 3 0 - 3
隊伍 A B C 得分
A - 0 3 3
B 3 - 0 3
C 0 3 - 3
給出n支隊伍的最終得分(即所有比賽均已結束),統計有多少種可能的分數表。
【輸入格式】
第一行包含一個正整數n,隊伍的個數。第二行包含n個非負整數,即每支隊伍的得分。
【輸出格式】
輸出僅一行,即可能的分數表數目。保證至少存在一個可能的分數表。
【樣例】
輸入 輸出
3
3 3 3 2
2
0 3 1
3
4 1 2 1
6
5 6 7 7 8 8 121
【數據規模】
數據 1 2~3 4~6 7~12 13~19 20~25
n 3 4 5 6 7 8
</span>
這道題就是簡單爆搜,加一個剪枝。
首先算出勝場和平場的數目。
之後就是直接搜咯,但貌似正解不是這樣的,誰想到可以留言。 時間也很長,過不了全部點,但貌似已經盡最大能力了。
Code:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int n,point[30];
void Input()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&point[i]);
}
int wi,pi;
int a[30],sum;
void dfs(int x,int y,int r1,int r2)
{
if(x==n)
{
if(point[x]==a[x])
{
sum++;
return ;
}
}
else if(y==n+1)
{
if(point[x]==a[x])
{
dfs(x+1,x+2,r1,r2);
}
}
else
{
if(r1)
{
a[x]+=3;
dfs(x,y+1,r1-1,r2);
a[x]-=3;
a[y]+=3;
dfs(x,y+1,r1-1,r2);
a[y]-=3;
}
if(r2)
{
a[x]+=1; a[y]+=1;
dfs(x,y+1,r1,r2-1);
a[x]-=1; a[y]-=1;
}
}
}
void Solve()
{
int ans=0; sum=0;
for(int i=1;i<=n;i++)
ans+=point[i];
wi=ans-(n*(n-1));
pi=wi-(n*(n-1)/2);
dfs(1,2,wi,pi);
}
void Output()
{
printf("%d\n",sum);
}
int main()
{
freopen("match.in","r",stdin);
freopen("match.out","w",stdout);
Input();
Solve();
Output();
return 0;
}
<span style="font-family:Microsoft YaHei;">聖誕樹
【題目描述】
聖誕節到了,FireDancer準備做一棵大聖誕樹。左圖爲聖誕樹的一個簡單結構。
這棵樹被表示成一組被編號的結點和一些邊的集合。結點從1到n編號。樹的根永遠是1。每個結點都有一個自身特有的數值,稱爲它的重。各個結點的重可能不同。對於一棵做完的樹來說,每條邊都有一個價值,若設這條邊e連接結點i和結點j,且i爲j的父結點(根是最老的祖先),則該邊的價值爲(j的所有子孫及它自己的重之和)*(e的單位價值ce)。
現在FireDancer想造一棵樹,使得樹上所有邊的總價值最小,並且所有的點都在樹上,因爲FireDancer喜歡大樹。
【輸入格式】
第一行兩個整數n和m(0<=n,m<=50000),表示結點總數和可供選擇的邊數。
下面一行有n個整數,依次表示每個結點的重。
下面m行,每行有3個正整數a,b,c,表示結點a和結點b之間有一個單位價值爲c的邊可供你造樹時選擇。
輸入中的所有數都小於216。
【輸出格式】
若無解,輸出“No Answer”,否則一個整數表示造樹的最小价值。
樣例輸入 輸出樣例
2 1
1 1
1 2 15 15
7 7
200 10 20 30 40 50 60
1 2 1
2 3 3
2 4 2
3 5 4
3 7 2
3 6 3
1 5 9
1210</span>
沒圖不好意思了。
其實就可以簡單等價成最短路,自己畫個圖就知道了。
把根節點和其他的邊最短路
要離開機房了。 要用longlong
Code:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#define LL unsigned long long
using namespace std;
LL val[51000];
struct node
{
LL x,y,d,next;
}a[110000]; LL len,first[51000];
LL n,m;
void ins(LL x,LL y,LL d)
{
len++;
a[len].x=x; a[len].y=y; a[len].d=d;
a[len].next=first[x]; first[x]=len;
}
void Input()
{
scanf("%I64d%I64d",&n,&m);
for(LL i=1;i<=n;i++)
scanf("%I64d",&val[i]);
len=0; memset(first,0,sizeof(first));
for(LL i=1;i<=m;i++)
{
LL x,y,d;
scanf("%I64d%I64d%I64d",&x,&y,&d);
ins(x,y,d); ins(y,x,d);
}
}
queue<LL>Q;
LL d[51000];
bool v[51000];
LL ans=0;
void Solve()
{
Q.push(1); memset(d,126,sizeof(d));
d[1]=0; memset(v,0,sizeof(v));
v[1]=1;
while(!Q.empty())
{
LL x=Q.front();
for(LL k=first[x];k;k=a[k].next)
{
LL y=a[k].y;
if(d[y]>d[x]+a[k].d)
{
d[y]=d[x]+a[k].d;
if(!v[y])
{
v[y]=true;
Q.push(y);
}
}
}
v[x]=false;
Q.pop();
}
for(LL i=2;i<=n;i++)
{
ans+=val[i]*d[i];
}
printf("%I64d\n",ans);
}
int main()
{
freopen("chris.in","r",stdin);
freopen("chris.out","w",stdout);
Input();
Solve();
return 0;
}