汕頭市隊賽SRM15
T1——czl SRM 15
眾所周知,czl家養了一只可♂愛的***(已屏蔽),那只東西很貪吃,所以czl家很多零食倉庫,然而這些倉庫裏有很多老鼠。
為了心愛的***,czl決定點燃純艾條,用煙熏老鼠。
共有N個倉庫,編號1-N。
假設陵陵在第i個倉庫點燃艾條,煙霧就會充滿該倉庫,並向左右擴散Ai 的距離,接著所有|i-j|<=Ai 的倉庫 j 的老鼠被消滅。
陵陵是個愛護環境的人,他想知道最少需要多少支艾條,才可以消滅所有老鼠。
【輸入格式】
第一行:一個正整數,代表 N。
第二行:N 個非負整數,第 i 個數代表 A i 。
【輸出格式】
第一行:一個整數,代表答案。
【樣例】
Inout:
5
2 3 3 3 3
Output:
1
【數據範圍】
20%的數據:N <= 20
60%的數據:N <= 10^3
100%的數據:N <= 5*10^5 ,Ai<=N
——————————————————————————
這道題就是用最少的線段覆蓋整個區間
這題我寫的貪心 把被包含的區間去掉之後 貪心做
#include<cstdio> #include<algorithm> #include<cstring> #define LL long long using namespace std; constView Codeint M=1e6+7,inf=0x3f3f3f3f; int read(){ int ans=0,f=1,c=getchar(); while(c<‘0‘||c>‘9‘){if(c==‘-‘) f=-1; c=getchar();} while(c>=‘0‘&&c<=‘9‘){ans=ans*10+(c-‘0‘); c=getchar();} return ans*f; } int cnt,n,ans,f[M],h[M],q[M]; struct node{int l,r;}e[M]; bool cmp(node a,node b){returna.l!=b.l?a.l<b.l:a.r>b.r;} int main() { int k; n=read(); for(int i=1;i<=n;i++) k=read(),e[i].l=max(1,i-k),e[i].r=min(i+k,n); sort(e+1,e+1+n,cmp); q[++cnt]=1; for(int i=2;i<=n;i++) if(e[i].r>e[q[cnt]].r) q[++cnt]=i; k=2; ans=1; int now=e[q[1]].r; while(k<=cnt){ while(k<cnt&&e[q[k+1]].l<=now+1) k++; ans++; now=e[q[k]].r; k++; }printf("%d\n",ans); return 0; }
T2——sxt SRM 15
為了加快社會主義現代化,建設新漁村,sxt決定給小漁村裏每座建築都連上互聯網,方便未來隨時隨地網購西瓜肥料。
小漁村很大,有 N 座建築,但地理位置偏僻,網絡信號很差。
一座建築有網,當且僅當滿足以下至少一個條件:
1、給中國移動交寬帶費,直接連網,花費為 A。
2、向另外一座有網的建築,安裝共享網線,花費為 B×兩者曼哈頓距離。
現在,騰騰已經統計出了所有建築的坐標。他想知道最少要多少費用才能達到目的。
【輸入格式】
第一行:三個正整數,代表 N、A、B。
接下來 N 行:每行兩個整數 X i 、Y i ,第 i 行代表第 i 座建築的坐標。
【輸出格式】
第一行:一個整數,代表答案。
【樣例】
Input
3 3 2
1 1
0 1
0 0
Output
7
【數據範圍】
30%的數據:N <= 3,A <= 50,B <= 5
60%的數據:N <= 100,A <= 1000,B <= 20
100%的數據:N <= 10^3 ,A <= 10^4 ,B <= 50,|Xi |,|Y i | < 2^15
——————————————————————————————————
這是道很裸的最小生成樹了 直接加一個點 向其他1-n連大小為A的邊就好了
我寫的prim可能會快點
#include<cstdio> #include<cstring> #include<algorithm> #define LL long long using namespace std; const int M=1e3+7; const LL inf=1e15; int read(){ int ans=0,f=1,c=getchar(); while(c<‘0‘||c>‘9‘){if(c==‘-‘) f=-1; c=getchar();} while(c>=‘0‘&&c<=‘9‘){ans=ans*10+(c-‘0‘); c=getchar();} return ans*f; } int n,S,A,B,vis[M]; LL x[M],y[M],map[M][M],d[M],ans; LL pabs(LL x){return x>=0?x:-x;} LL calc(int s1,int s2){return pabs(x[s1]-x[s2])+pabs(y[s1]-y[s2]);} void prim(){ d[S]=0; vis[S]=1; for(int i=1;i<=n;i++) d[i]=map[S][i]; for(int i=1;i<=n;i++){ double mn=inf; int h=0; for(int j=1;j<=n;j++) if(!vis[j]&&mn>d[j]) mn=d[j],h=j; ans+=mn; d[h]=0; vis[h]=1; for(int j=1;j<=n;j++) if(!vis[j]&&map[h][j]<d[j]) d[j]=map[h][j]; } } int main() { n=read(); A=read(); B=read(); S=0; for(int i=1;i<=n;i++) x[i]=read(),y[i]=read(); for(int i=1;i<=n;i++) map[S][i]=map[i][S]=A; for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) map[i][j]=map[j][i]=B*calc(i,j); prim(); printf("%lld\n",ans); return 0; }View Code
T3——yyl SRM 15
當了集訓隊爺後的yyl為了當上renying踏上了健身之路,他想讓s(你可以認為這個是其他男同學的那啥)的值盡量少,以在妹子面前襯托他的健美。為了達到他的目的,他希望你對序列進行旋轉操作,一次旋轉操作可以使序列中的所有元素前移一位,並使 s1移動到 sn ,具體來說是這樣的:
————————————————————————————————————-
這道題我們可以破環成鏈 每次相當於把1-n 挪一位相減求和
我們可以發現每個數對答案貢獻的函數是線性的不然就是分段函數有個拐點(先遞減後遞增)
每一位的拐點等於 i+1-v【i】 如果小於0就是一直遞增
然後每次移動區間維護一下各種信息就好辣
(zz地比賽沒寫出來 賽後調了一個多小時.QAQ
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define LL long long using namespace std; const int M=4e6+7; int read(){ LL ans=0,f=1,c=getchar(); while(c<‘0‘||c>‘9‘){if(c==‘-‘) f=-1; c=getchar();} while(c>=‘0‘&&c<=‘9‘){ans=ans*10+(c-‘0‘); c=getchar();} return ans*f; } int n,m; int v[M],f[M],cnt=1; LL sum,ans,now; struct node{int pos; LL h;}e[M]; bool cmp(node a,node b){return a.h<b.h;} int main() { n=read(); m=n<<1; for(int i=1;i<=n;i++) v[i]=read(),v[i+n]=v[i],sum+=abs(v[i]-i); for(int i=1;i<=m;i++) f[i]=-1,e[i].pos=i,e[i].h=i+1-v[i];//v[i]==y-x+1 ans=sum; sort(e+1,e+1+m,cmp); while(e[cnt].h<=1&&cnt<=m) f[e[cnt].pos]=1,cnt++; for(int i=2;i<=n;i++) now+=f[i]; for(int i=2;i<=n;i++){ sum+=now; sum-=abs(v[i-1]-1); sum+=abs(v[i+n-1]-n); now-=f[i]; while(e[cnt].h<=i&&cnt<=m){ int x=e[cnt].pos; cnt++; f[x]=1; if(i<x&&x<i+n-1) now+=2; } now+=f[i+n-1]; ans=min(ans,sum); }printf("%lld\n",ans); return 0; }View Coded
當然因為 v【i】<=n 所以可以利用桶排算出每個值排序後在哪個區間,然後放進那個區間 這樣就是o(n)了
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define LL long long using namespace std; const int M=4e6+7; int read(){ LL ans=0,f=1,c=getchar(); while(c<‘0‘||c>‘9‘){if(c==‘-‘) f=-1; c=getchar();} while(c>=‘0‘&&c<=‘9‘){ans=ans*10+(c-‘0‘); c=getchar();} return ans*f; } int n,m; int v[M],f[M],s[M],l[M],r[M],k,cnt=1; LL sum,ans,now; struct node{int pos; LL h;}e[M],q[M]; bool cmp(node a,node b){return a.h<b.h;} int main() { n=read(); m=n<<1; for(int i=1;i<=n;i++) v[i]=read(),v[i+n]=v[i],sum+=abs(v[i]-i); for(int i=1;i<=m;i++) f[i]=-1,e[i].pos=i,e[i].h=max(1,i+1-v[i]),s[e[i].h]++;//v[i]==y-x+1 int last=0; for(int i=1;i<=m;i++)if(s[i]) l[i]=last+1,r[i]=last+s[i],last=r[i]; for(int i=1;i<=m;i++) q[l[e[i].h]]=e[i],l[e[i].h]++; ans=sum; while(q[cnt].h<=1&&cnt<=m) f[q[cnt].pos]=1,cnt++; for(int i=2;i<=n;i++) now+=f[i]; for(int i=2;i<=n;i++){ sum+=now; sum-=abs(v[i-1]-1); sum+=abs(v[i+n-1]-n); now-=f[i]; while(q[cnt].h<=i&&cnt<=m){ int x=q[cnt].pos; cnt++; f[x]=1; if(i<x&&x<i+n-1) now+=2; } now+=f[i+n-1]; ans=min(ans,sum); }printf("%lld\n",ans); return 0; }View Code
汕頭市隊賽SRM15