ABC挺顺的,D卡飞我是没想到的…(btw还好wa1不算罚时不然我直接炸开(这里因为算错了一个复杂度,等会补上来,白痴问题我这就公开处刑我自己
D
2s时限 ,我寻思cf的评测姬不会爆吧,那这不是直接搞就完事(
就搁那硬扫1e9,没注意中间sqrt函数也有个复杂度没算进去
后来是打表看了眼上限然后预处理做的
也整挺短一code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
vector<int> vec;
int main() {
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
for(ll i = 3; i <= 44721; i += 2) {
ll x = (i * i + 1) / 2;
if(x * x - (x - 1) * (x - 1) == i * i) vec.push_back(x);
}
// cout << vec.size();
int T;
cin >> T;
while(T--) {
int n;
cin >> n;
cout << upper_bound(vec.begin(), vec.end(), n) - vec.begin() << endl;
}
}
1487 E. Cheap Dinner
题意: 有4种食物,设为ABCD,各有 n 1 , n 2 , n 3 , n 4 n1,n2,n3,n4 n1,n2,n3,n4个,每个都有一个 c o s t cost cost,同时 A B AB AB之间有 m 1 m1 m1种冲突的搭配, B C BC BC之间有 m 2 m2 m2种冲突的搭配, C D CD CD之间有 m 3 m3 m3种冲突的搭配,现在要四种食物各取一个问最少花费
思路: 因为AD之间不冲突,可以先把整个问题分成两部分考虑(A-B,C-D),
在考虑A-B的时候,对于每个B(因为B在中间,由B选择A没有后效性)贪心选择cost最小的A,判断A是否在m1个冲突里可以用set的find,对于每个B存一个set,总体复杂度在 O ( n l o g m ) O(nlogm) O(nlogm)级别,(可以证明枚举每个A的时候,如果最开始的每次都恰巧冲突,最多的冲突次数大概是 m+n2 次,) 直接把答案加在B里就行
C-D同理,对每个C存set,把答案加在C里
最后也是同理把两部分和在一起,这里对B或C存set都行
参考YT
codeforces_SAMPLE I
code:
#include <bits/stdc++.h>
using namespace std;
const int N = 150010, M = 200010;
const int inf = 5e8;
struct node {
int cost, idx;
bool operator < (const node & obj) const{
return cost < obj.cost;
}
}mpa[N], mpb[N], mpc[N], mpd[N];
set<int> stb[N], stc[N], ss[N];
int main() {
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int numa, numb, numc, numd;
cin >> numa >> numb >> numc >> numd;
for(int i = 1; i <= numa; ++ i) {
// a
mpa[i].idx = i;
cin >> mpa[i].cost;
}
for(int i = 1; i <= numb; ++ i) {
// b
mpb[i].idx = i;
cin >> mpb[i].cost;
}
for(int i = 1; i <= numc; ++ i) {
// c
mpc[i].idx = i;
cin >> mpc[i].cost;
}
for(int i = 1; i <= numd; ++ i) {
// d
mpd[i].idx = i;
cin >> mpd[i].cost;
}
int m1, m2, m3;
cin >> m1;
for(int i = 1, u, v; i <= m1; ++ i) {
// a and b (in b
cin >> u >> v;
stb[v].insert(u);
}
cin >> m2;
for(int i = 1, u, v; i <= m2; ++ i) {
// b and c (in c
cin >> u >> v;
ss[v].insert(u);
}
cin >> m3;
for(int i = 1, u, v; i <= m3; ++ i) {
// c and d (in c
cin >> u >> v;
stc[u].insert(v);
}
sort(mpa + 1, mpa + numa + 1); // a and b
for(int i = 1; i <= numb; ++ i) {
bool flag = 0;
for(int j = 1; j <= numa; ++ j) {
if(stb[mpb[i].idx].find(mpa[j].idx) == stb[mpb[i].idx].end()) {
mpb[i].cost += mpa[j].cost;
flag = 1;
break;
}
}
if(!flag) {
mpb[i].cost = inf;
}
}
sort(mpd + 1, mpd + numd + 1); // c and d
for(int i = 1; i <= numc; ++ i) {
bool flag = 0;
for(int j = 1; j <= numd; ++ j) {
if(stc[mpc[i].idx].find(mpd[j].idx) == stc[mpc[i].idx].end()) {
mpc[i].cost += mpd[j].cost;
flag = 1;
break;
}
}
if(!flag) {
mpc[i].cost = inf;
}
}
sort(mpb + 1, mpb + numb + 1); // (a and b (in b)) and (c and d (in c))
for(int i = 1; i <= numc; ++ i) {
bool flag = 0;
for(int j = 1; j <= numb; ++ j) {
if(ss[mpc[i].idx].find(mpb[j].idx) == ss[mpc[i].idx].end()) {
mpc[i].cost += mpb[j].cost;
flag = 1;
break;
}
}
if(!flag) {
mpc[i].cost = inf;
}
}
sort(mpc + 1, mpc + numc + 1);
if(mpc[1].cost >= inf) {
cout << -1;
return 0;
}
else {
cout << mpc[1].cost;
}
}
代码很多部分都是cv了改下,没有想得那么烦
btw,cf数据有点水啊,刚有个地方打错数组都能给我过23个点,还以为是边界啥的出问题了(= =
F
数位dp
挖坑
- eg 111111 × 6 = 1111111 − 111111 × 4 − 1 111111\times 6=1111111-111111 \times 4-1 111111×6=1111111−111111×4−1, 1 × 6 = 11 − 1 × 5 1\times 6=11-1\times 5 1×6=11−1×5,所以表明每一个长度的串1都最多用不会超过6次
- 低位的1不会产生进位,即不会对高位产生影响,