生活随笔
收集整理的這篇文章主要介紹了
8.23打架学习一个
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
先看題目: T1:數正方形,數學簽到題,找規律; T2:取數,看起來很眼熟的一道題,并且何某8.22時告誡我們要考動規。所以顯然。。。不是動規。動規動規念著念著就成“堆”了。 T3:葡萄酒交易,唯一的一道動規+最小生成樹+狀態亞索。
T1: 在n * n的點陣中任取4個點,回答: 問題1:這4個點恰好是“正放”的正方形的4個頂點的方案數是多少? 問題2:這4個點恰好是正方形(包括“正放”和“斜放”)的4個頂點的方案數是多少?
下圖為一個4*4的點陣,上圖表示一種“正放”的方案,下圖表示一種“斜放”的方案。
int main()
{
//freopen (
"count.in" ,
"r" ,stdin);
//freopen (
"count.out" ,
"w" ,stdout);re(n);re(k);
for (i=
1 ;i<=n-
1 ;i++)ans1+=(n-i)
*( n-i);
for (i=
1 ;i<=n-
2 ;i++)ans2+=i
*i *( (n-
1 )-i);
if (k==
1 )
printf (
"%I64d " ,ans1
%mod );
else printf (
"%I64d " ,(ans1+ans2)
%mod );
}
隨便找找規律就可以了。
T2:n個整數組成的一個環,現在要從中取出m個數,取走一個數字就不能取跟它相鄰的數字(相鄰的數不能同時取)。要求取出的數字的總和盡可能大,問這個最大和是多少? 如果無解,請輸出“Error!” 輸入 : 第一行包含兩個正整數n、m。 第二行為n個整數Ai。 輸出:僅一個整數,表示所求結果。如果無解輸出“Error!”,不包含引號。 樣例數據: in:7 3 1 2 3 4 5 6 7 out:15 in:7 4 1 2 3 4 5 6 7 out:Error! in:8 4 8 5 6 2 3 4 8 9 out:25
炸一看是動規,不過一看動規是O(2n方),怎么就變成堆了呢? 利用結構體,分別記錄每個數的編號,值,左邊值,右邊值,然后放進一個大根堆里面。每次取出堆頂的數,標記左右不可選的數,用ans把它加起來。注意還沒完,現在要生成一個新的數,值為(左+右-當前數值),并且更新左數和右數,如此,若當前選擇并非最優,就可以重新選擇。 這。只能膜拜想出這個方法的神犇為敬了。
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<queue>
#include<cmath>
using namespace std ;
priority_queue<pair<
int ,
int > >q;
const int MAX=-
999999999 ;
const int maxn=
400200 ;
inline void re(
int &d)
{
char t=getchar();
bool f=
false ;
while (t<
'0' ||t>
'9' ){
if (t==
'-' )f=
true ;t=getchar();}
for (d=
0 ;t>=
'0' &&t<=
'9' ;t=getchar())d=d*
10 +t-
'0' ;
if (f==
true )d=-d;
}
int n,m,a,b,c,d,e,ans=
0 ,tot=
0 ;
int p[maxn],l[maxn],r[maxn];
bool used[maxn];
int main()
{re(n);re(m);
for (a=
1 ;a<=n;a++){re(p[a]); l[a]=a-
1 ;r[a]=a+
1 ; q.push(make_pair(p[a],a));tot++;}l[
1 ]=n;r[n]=
1 ;
if (m>(n/
2 )){
printf (
"Error!" );
return 0 ;}
while (m!=
0 ){a=q.top().second;q.pop();
if (used[a]==
true )
continue ;ans+=p[a];tot++;p[tot]=p[l[a]]+p[r[a]]-p[a]; used[a]=
true ;used[l[a]]=
true ;used[r[a]]=
true ;l[tot]=l[l[a]];r[tot]=r[r[a]];l[r[r[a]]]=tot;r[l[l[a]]]=tot; q.push(make_pair(p[tot],tot)); m--;}
printf (
"%d" ,ans);
return 0 ;
}
T3: 啊不想寫了,狀態亞索記錄某點是否在集合之中,然后用最小生成樹亂搞一下就可以了。
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cmath>
using namespace std ;
const int inf=
1e9 ;
const int maxn=(
1 <<
17 );
struct node{
int x,y,v;
}wine[
200 ];
int i,j,n,m,toot,a[
20 ],father[
20 ],sum[maxn],cost[maxn],f[maxn];
bool cmp(node x,node y){
return x.v<y.v;}
inline void re(
int &d)
{
bool f=
false ;
char t=getchar();
while (t<
'0' ||t>
'9' ){
if (t==
'-' )f=
true ;t=getchar();}
for (d=
0 ;t>=
'0' &&t<=
'9' ;t=getchar())d=(d<<
3 )+(d<<
1 )+t-
'0' ;
if (f==
true )d=-d;
}
int getfather(
int x)
{
if (x!=father[x])father[x]=getfather(father[x]);
return father[x];
}
int kru(
int s)
{
int i,tot=
0 ,mincost=
0 ,cnt=
0 ;
for (i=
0 ;i<n;i++){father[i]=i;
if ((s>>i)&
1 )tot++;}
for (i=
1 ;i<=m;i++){
if (((s>>wine[i].x)&
1 )&&((s>>wine[i].y)&
1 )){
int fx=getfather(wine[i].x);
int fy=getfather(wine[i].y);
if (fx!=fy){father[fx]=fy;cnt++;mincost+=wine[i].v;}} }
if (cnt+
1 !=tot)
return inf;
else return mincost;
}
int main()
{re(n);re(m);
for (i=
0 ;i<n;i++)re(a[i]);
for (i=
1 ;i<=m;i++){re(wine[i].x);re(wine[i].y);re(wine[i].v);}sort(wine+
1 ,wine+
1 +m,cmp);toot=(
1 <<n)-
1 ;
for (i=
0 ;i<=toot;i++)
for (j=
0 ;j<n;j++){
if ((i>>j)&
1 )sum[i]+=a[j];}
for (i=
0 ;i<=toot;i++){
if (sum[i]==
0 )cost[i]=kru(i);
else cost[i]=inf;}
for (i=
1 ;i<=toot;i++)f[i]=inf;f[
0 ]=
0 ;
for (i=
0 ;i<=toot;i++){
if (sum[i]!=
0 )
continue ;
for (j=
1 ;j<=toot;j++){
if (sum[j]!=
0 )
continue ;f[i|j]=min(f[i|j],f[i]+cost[j]);}}
if (f[toot]==inf)
printf (
"Impossible\n" );
else printf (
"%d\n" ,f[toot]);
return 0 ;
}
就這樣吧。
總結
以上是生活随笔 為你收集整理的8.23打架学习一个 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。