0 少女覺
在幽暗的地靈殿中,居住着一位少女,名爲古明地覺。
據說,從來沒有人敢踏入過那座地靈殿,因爲人們恐懼於覺一族擁有的能力——讀心。
掌控人心者,可控天下。
咳咳。
人的記憶可以被描述爲一個黑塊(B)與白塊(W)的序列,其中情感值被定義爲序列中黑塊數量與白塊數量之比。
小五口在發動讀心術時,首先要解析人的記憶序列,因此,需要將序列分割爲一些段,並且要求每一段記憶序列的情感值都相等。
下面給出兩個例子:
BWWWBB -> BW + WWBB (Ratio=1:1)
WWWBBBWWWWWWWWWB -> WWWB + BBWWWWWW + WWWB (Ratio=3:1)
現在小五手上有一個人的記憶序列,她想要知道,如何將手中的記憶序列分成儘可能多的段呢?
對於10%的數據,n<=15
對於20%的數據,n<=500
另有30%的數據,K=1
另有30%的數據,K<=50
對於100%的數據,N<=10^5 , 序列長度不超過10^9
保證對於全部測試點,輸入文件行數不超過2.5*10^6
可以發現黑塊與白塊的比是確定的,是所有黑塊比上所有白塊,因而每一個小序列的比就是這個總比值
那麼就按讀入順序往下做,每次一滿足比值就馬上記錄答案
#include <cstdio>
#include <algorithm>
using namespace std;
int t,n,ans;
long long suma,sumb,wa,wb,p;
int a[100005],b[100005];
void read(int i){
char ch=getchar();
a[i]=0;
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9'){
a[i]=a[i]*10+ch-'0';
ch=getchar();
}
while (ch!='B'&&ch!='W') ch=getchar();
if (ch=='B') b[i]=1,sumb+=a[i]; else b[i]=0,suma+=a[i];
}
long long pk(long long s,long long a,long long b){
if ((a*s)%b==0) return (a*s)/b; else return -1;
}
int main(){
freopen("silly.in","r",stdin);
freopen("silly.out","w",stdout);
scanf("%d",&t);
for (;t;t--){
scanf("%d",&n);
suma=0,sumb=0,ans=0;
for (int i=1;i<=n;i++){
read(i);
}
if (suma==0||sumb==0){
printf("%d\n",max(suma,sumb));
continue;
}
wa=0;wb=0;
for (int i=1;i<=n;i++){
if (b[i]==0) {
long long p=pk(wb,suma,sumb);
if (p>wa&&p<=wa+a[i]) ans++;
wa+=a[i];
}
else
{
long long p=pk(wa,sumb,suma);
if (p>wb&&p<=wb+a[i]) ans++;
wb+=a[i];
}
}
printf("%d\n",ans);
}
}
1 靈知的太陽信仰
在熾熱的核熔爐中,居住着一位少女,名爲靈烏路空。
據說,從來沒有人敢踏入過那個熔爐,因爲人們畏縮於空所持有的力量——核能。
核焰,可融真金。
咳咳。
每次核融的時候,空都會選取一些原子,排成一列。然後,她會將原子序列分成一些段,並將每段進行一次核融。
一個原子有兩個屬性:質子數和中子數。
每一段需要滿足以下條件:
1、同種元素會發生相互排斥,因此,同一段中不能存在兩個質子數相同的原子。
2、核融時,空需要對一段原子加以防護,防護罩的數值等於這段中最大的中子數。換句話說,如果這段原子的中子數最大爲x,那麼空需要付出x的代價建立防護罩。求核融整個原子序列的最小代價和。
設 f[i] 爲 i 與 i+1 之間分開,到i爲止的代價和
預處理出 l[i] 表示 i 最早的相同質子數的位置
易得,這樣的轉移是的
可以用單調隊列維護合法的點組成的隊列,每次更新f[i]只需循環合法的點,每次又都取出不合法的點
因爲前一個點不能轉移的點,後一個點也不能通過這個點轉移來
(因爲可能TLE所以稍微卡了個常?)
比如register , 快讀 ,if 改爲(xx條件xx?xx:xx)
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=100005;
const int inf=2000000000;
int n;
int l[N],p[N],w[N];
int f[N],e[N];
int read(){
char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
int x=0;
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x;
}
int main(){
freopen("array.in","r",stdin);
freopen("array.out","w",stdout);
n=read();
int ab;
for (register int i=1;i<=n;i++){
ab=read();w[i]=read();
l[i]=(l[i-1]>p[ab]?l[i-1]:p[ab]),
p[ab]=i,f[i]=inf;
}
int h=1,t=1;
f[1]=w[1],e[1]=1;
for (register int i=2;i<=n;i++){
while (h<=t&&e[h]<=l[i]) ++h;
while (h<=t&&w[i]>w[e[t]]) --t;
e[++t]=i;
for (int j=h+1;j<=t;j++)
f[i]=(f[i]>f[e[j-1]]+w[e[j]]?f[e[j-1]]+w[e[j]]:f[i]);
f[i]=(f[i]>f[l[i]]+w[e[h]]?f[l[i]]+w[e[h]]:f[i]);
}
printf("%d",f[n]);
}
2 多段線性函數
哎嗨,據dalao言此題是爲閱讀題
就,題目的函數公式,相當於y到每個區間的距離
因爲要求的函數值儘可能小,所以當y在區間內xi肯定是取y ,這時對函數值無貢獻;當y不在區間內xi也一定是取與y更近的端點
所以就只與端點有關
就把所有端點堆一起排個序,取中間兩個就是答案
啊哈,中位數
#include <cstdio>
#include <algorithm>
using namespace std;
int n;
int a[200005];
int main(){
freopen("linear.in","r",stdin);
freopen("linear.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d%d",&a[i],&a[i+n]);
sort(a+1,a+1+n*2);
printf("%d %d",a[n],a[n+1]);
}
3 DY引擎
BOSS送給小唐一輛車。小唐開着這輛車從PKU出發去ZJU上課了。
衆所周知,天朝公路的收費站超多的。經過觀察地圖,小唐發現從PKU出發到ZJU的所有路徑只會有N(2<=N<=300)個不同的中轉點,其中有M(max(0, N-100) <=M<=N)個點是天朝的收費站。N箇中轉點標號爲1…N,其中1代表PKU,N代表ZJU。中轉點之間總共有E(E<=50,000)條雙向邊連接。
每個點還有一個附加屬性,用0/1標記,0代表普通中轉點,1代表收費站。當然,天朝的地圖上面是不會直接告訴你第i個點是普通中轉點還是收費站的。地圖上有P(1<=P<=3,000)個提示,用[u, v, t]表示:[u, v]區間的所有中轉點中,至少有t個收費站。數據保證由所有提示得到的每個點的屬性是唯一的。
車既然是BOSS送的,自然非比尋常了。車子使用了世界上最先進的DaxiaYayamao引擎,簡稱DY引擎。DY引擎可以讓車子從U瞬間轉移到V,只要U和V的距離不超過L(1<=L<=1,000,000),並且U和V之間不能有收費站(小唐良民一枚,所以要是經過收費站就會停下來交完錢再走)。
DY引擎果然是好東西,但是可惜引擎最多隻能用K(0<=K<=30)次。
這題可以拆分成兩部分,找出收費站和找出最短路
其中找出收費站需要用到差分約束系統
差分約束系統
用於題目給出形如: 的約束條件,求狀態
首先我們盪開筆墨,先假設我們有一張有向圖,已經求出了最短路,表示從1到i的最短路
現在有一條i到j的邊,表示爲
當然有
那麼我們反過來,回到給出的約束條件,就相當於從j到i連一條權值爲k的有向邊
求出的狀態當然也就是用最短路,快樂跑spfa
當然有很多題目不會直接給出約束條件,要自己從題目描述中找
再回到這道題
條件:[u, v]區間的所有中轉點中,至少有t個收費站
設表示到的收費站總數,則條件轉化爲
再移下項,就是
這就相當於差分約束系統的條件了,求出狀態後即爲是否有收費站
然後就是用最短路跑DP啦
跑這個最短路呢,要記錄第幾個點,跳了幾次
#include <cstdio>
#include <cstring>
using namespace std;
const int N=50002;
int n,m,e,p,l,k;
int ls[305],ne[N],y[N],w[N],bz[305],cnt;
int s[305],v[N*10],g[N*10],b[N][35],d[N*10];
int f[305][35],a[305][305];
void ad(int _u,int _v,int _w){
ne[++cnt]=ls[_u],ls[_u]=cnt,y[cnt]=_v,w[cnt]=_w;
}
void spfa1(){
memset(s,0x3f,sizeof s);
for (int i=1;i<=n;i++)
ad(i,i-1,0),ad(i-1,i,1);
int h=0,t=1;
v[1]=n;s[n]=m;bz[n]=1;
while (h<t){
int u=ls[v[++h]];
while (u!=-1){
if (s[v[h]]+w[u]<s[y[u]]){
s[y[u]]=s[v[h]]+w[u];
if (bz[y[u]]==0){
bz[y[u]]=1;
v[++t]=y[u];
}
}
u=ne[u];
}
bz[v[h]]=0;
}
for (int i=n;i>=1;i--) s[i]=s[i]-s[i-1];
}
void read(){
scanf("%d%d%d%d%d%d",&n,&m,&e,&p,&l,&k);
memset(a,0x3f,sizeof a);
for (int i=1;i<=e;i++){
int u,_v,_w;
scanf("%d%d%d",&u,&_v,&_w);
if (_w<a[u][_v]) a[u][_v]=a[_v][u]=_w;
}
for (int i=0;i<=n;i++) ls[i]=-1;
for (int i=1;i<=p;i++){
int _u,_v,_t;
scanf("%d%d%d",&_u,&_v,&_t);
ad(_v,_u-1,-_t);
}
}
void floyed(){
for (int k=1;k<=n;k++)
for (int i=1;i<=n;i++)
if (i!=k)
for (int j=1;j<=n;j++)
if (i!=j&&j!=k&&s[k]==0&&a[i][k]!=a[0][0]&&a[k][j]!=a[0][0])
a[i][j]=(a[i][j]>a[i][k]+a[k][j]?a[i][k]+a[k][j]:a[i][j]);
}
void spfa2(){
cnt=0;
int h=0,t=1;
memset(b,0,sizeof b);
memset(f,0x3f,sizeof f);
b[1][0]=1,f[1][0]=0;
v[1]=1,d[1]=0;
while (h<t){
int x=v[++h],y=d[h];
for (int i=2;i<=n;i++)
if (a[x][i]!=a[0][0]){
if (f[x][y]+a[x][i]<f[i][y]){
f[i][y]=f[x][y]+a[x][i];
if (b[i][y]==0){
b[i][y]=1;
v[++t]=i;
d[t]=y;
}
}
if (y+1<=k&&a[x][i]<=l&&f[x][y]<f[i][y+1]){
f[i][y+1]=f[x][y];
if (b[i][y+1]==0){
b[i][y+1]=1;
v[++t]=i;
d[t]=y+1;
}
}
}
b[x][y]=0;
}
}
void print(){
int ans=1000000000;
for (int i=0;i<=k;i++)
ans=(ans>f[n][i]?f[n][i]:ans);
printf("%d",ans);
}
int main(){
read();
spfa1();
floyed();
spfa2();
print();
}