t1:最失敗的一道題,其實就是道水題,好幾種寫法,一種都沒想出來。
題意轉化後就是:每個數可以選a[i]和a[i]-k,最後求使1,2,3,...,t都存在的最大的t+1和最多能讓多少個數小於等於t。
為什麼第一問可以轉化成求有多少個數小於等於t呢?首先不大於k的怪物可以直接殺死,然後大於k的怪物顯然當且僅當血量小於等於t時才可能被用第二種操作殺死,所以當t最大一定是第二問最優的情況。所以第二問做完後直接掃一邊就是第一問的答案。
考慮第二問怎麼求:
方法一:二分答案。二分t判斷可行性即可,沒有任何坑點。$o(n\log n)$
方法二:直接迴圈。c記錄每個數有多少個。從1列舉,若 c[i]>0 則 c[i]-- 否則 c[i+k]--,某個數小於0了就終止迴圈。$o(n)$
方法三:若a[i]>k則連無向邊否則連自環。考慮這個圖的每個連通塊,如果邊數等於點數-1(也就是一棵樹),則必然有乙個數取不到(顯然這個數要選最大的那個),否則塊內所有數都能取到。並查集維護連通塊即可。$o(n\alpha(n))$
方法四:繼續方法三的思想,每個塊dfs一遍就可以求出塊內的點數和邊數了。$o(n)$
前兩種簡直是無腦方法我竟然都沒想到,後面兩種應該是乙個常用套路,以後發現數的範圍也是$o(n)$級別的話就要從數的角度考慮了(比如說建圖或生成函式做fft)
方法一:
1 #include2 #include3#define rep(i,l,r) for (int i=l; i<=r; i++)
4using
namespace
std;56
const
int n=100100;7
intn,k,a[n],ans;
8bool
b[n];910
int jud(int
mid)
14if (a[i]>mid)
15if (!b[a[i]-k]) b[a[i]-k]=1; else b[a[i]]=1;16
}17 rep(i,1,mid) if (!b[i]) return0;
18return1;
19}2021
intmain()
33int l=1,r=a[n]; ans=0;34
while (l<=r)
38int s=0;39
for (; s1]<=k || a[s+1]-k<=ans); s++);
40 printf("
%d %d\n
",s,min(n,ans+1
));41
return0;
42 }
方法二:
1 #include2 #include3#define rep(i,l,r) for (int i=l; i<=r; i++)
4using
namespace
std;56
const
int n=100100;7
intn,k,ans,a[n],c[n];89
intmain()
20 rep(i,1,n) if (a[i]<=k || a[i]-k<=s-1) ans++;
21 printf("
%d %d\n
",ans,min(n,s));
22return0;
23 }
方法四:
1 #include2 #include3 #include4#define rep(i,l,r) for (int i=l; i<=r; i++)
5#define for(i,x) for (int i=h[x],k; i; i=nxt[i])
6using
namespace
std;78
const
int n=200100;9
intn,k,ans,mx,cnt,tot,b[n],vis[n],bel[n],a[n],pe[n],pv[n],to[n],nxt[n],h[n];
10 vectorv[n];
1112
void add(int u,int v)
1314
void dfs(int x,int fa,int
co)18
19int
main()
t2:首先參考[jsoi2017]原力,這是乙個套路,但是只有80分。
考慮一種做法:先求出圖的一棵生成樹。假設三角形有至少一條邊在樹上,那麼列舉一條非樹邊,直接看fa[u]是否和v相鄰即可。如果沒有滿足條件的邊則說明這棵樹上沒有邊在三角形上,刪去所有樹邊。重複以上操作即可,複雜度$o(\frac)$。
這個做法當n在4000左右時顯然會很大,但這個時候直接bitset搞一下就可以了,複雜度$o(mn/64)$。
綜合以上兩種方法即可拿到滿分。
80分:
#include#include#include
#include
#include
#define rep(i,l,r) for (int i=l; i<=r; i++)typedef
long
long
ll;using
namespace
std;
const
int n=1000100,p=100003,p1=1000003
;int n,m,u,v,cnt,tot,d[n],id[n],to[n<<1],nxt[n<<1],h[n],hash1[p1+100],hash2[p1+100],s[210][210
];void add(int u,int v)
void hash(int u,int v)
int find(int u,int
v)int
main()
}rep(i,
1,m) scanf("
%d%d
",&u,&v),add(u,v),add(v,u),d[u]++,d[v]++,hash(min(u,v),max(u,v));
rep(i,
1,n) if (d[i]>=si) id[++tot]=i;
rep(i,
1,tot-2) rep(j,i+1,tot-1) rep(k,j+1
,tot)
if (find(id[i],id[j]) && find(id[j],id[k]) &&find(id[i],id[k]))
rep(i,
1,n) if (d[i]}
return0;
}
方法二(bitset):
#include#include#include
#define rep(i,l,r) for (int i=l; i<=r; i++)
using
namespace
std;
const
int n=100010
;int
n,m,u,v,u[n],v[n];
bitset
<4010>a[4010
];int
main()}}
return0;
}
滿分:
1 #include2 #include3#define rep(i,l,r) for (int i=(l); i<=(r); i++)
4 typedef long
long
ll;5
using
namespace
std;67
const
int n=100100,m=4200100;8
int n,m,tot,a[5000][200
],h[m],x[m],y[m],h1[m],nxt1[m],fa[n],nxt[n],used[n],que[n];910
int add(int a, int
b)15
16int findh(int a, int
b)23
return0;
24}2526
void fin(int i, int j, int
k)32
33int
alg1()43}
44return0;
45}4647
intalg2()
61 ptr =h[ptr];62}
63 p++;64}
65}66for (int i = 1; i <= tot; i++)
67if ((x[i] != fa[x[i]]) && (y[i] != fa[x[i]]) && (findh(y[i], fa[x[i]]) == 1
)) 70}71
return0;
72}7374
intmain()88}
89if (n <= 5000) alg1(); else
alg2();
90return0;
91 }
t3:考慮只有第一種概率模型的情況,從角的角度考慮。設同色三角形個數為$a$,異色為$b$,同色角個數x,異色$y$。則有$x=3a+b,y=2b$,解得$a=\frac$
2018計蒜客初賽1
又到了一年一度的計蒜之道,第二次參加計蒜之道,但願今年能在去年的基礎上有個新突破 第一場,由於時間限制,只寫了乙個簽到題,就此拉開了本年度計蒜之道 思路 這題這題其實思路倒是蠻清晰的,就是不斷維護陣列最大值,關鍵就是邊界處理問題,考慮清楚還挺有簽到意味 include include include...
NOIP2018模擬9 15總結
就是這樣 分數100 80 60 240 rank1 暴力真是爽 t1題意 有n個點,m條邊,k個特殊點,邊權為1 求每個點到離他最遠的特殊點的最短距離 nk 10000000 顯然暴力 t1 include define n 300001 using namespace std int i,j,k...
計蒜客NOIP模擬賽 小區劃分
題面 資料範圍不大,顯然的dp模型。狀態也很容易定出來 設f i j 表示把前i個單元樓劃分成j個小區的最大擁擠程度。那麼有動規方程 f i j ma x f k j 1 abs sum a i sum a k s umb i s umb k 時間複雜度o n2k 主要是注意小細節,要麼對f i 1...