表示当前至多放重量为的青蛙的底座的最大高度。
按重量从大到小排序后即可。
#include
using namespace std ;
int dp[100000000 + 10] ;
int main()
{
std::ios::sync_with_stdio(false) , cin.tie(0) ;
int n , d ;
cin >> n >> d ;
vector> v(n) ;
for(int i = 0 ; i < n ; i ++)
{
//l w h
for(int j = 0 ; j < 3 ; j ++) cin >> v[i][j] ;
//w l h
swap(v[i][0] , v[i][1]) ;
}
sort(v.begin() , v.end()) ;
reverse(v.begin() , v.end()) ;
int ans = 0 ;
for(int i = 0 ; i < n ; i ++)
{
int w = v[i][0] ;
int l = v[i][1] ;
int h = v[i][2] ;
if(dp[w] + l > d) ans ++ ;
for(int j = 1 ; j <= w - 1 && j + w <= 100000000 ; j ++)
dp[j] = max(dp[j] , dp[j + w] + h) , dp[j] = min(dp[j] , d + 1) ;
}
cout << ans << '\n' ;
return 0 ;
}
温暖的签到题。
#include
using namespace std ;
int main()
{
std::ios::sync_with_stdio(false) , cin.tie(0) ;
int n ;
cin >> n ;
bool flag = true ;
for(int i = 1 ; i <= n ; i ++)
{
string s ;
cin >> s ;
if(s[0] >= '1' && s[0] <= '9')
{
int now = 0 ;
for(int i = 0 ; i < s.size() ; i ++)
now = now * 10 + (s[i] - '0') ;
if(now != i) flag = false ;
}
else if(s[0] == '0') flag = false ;
}
if(flag) cout << "makes sense\n" ;
else cout << "something is fishy\n" ;
return 0 ;
}
温暖的签到题。
#include
using namespace std ;
int main()
{
std::ios::sync_with_stdio(false) , cin.tie(0) ;
int n ;
cin >> n ;
vector vis(366 , false) ;
for(int i = 0 ; i < n ; i ++)
{
int x ;
cin >> x ;
vis[x] = true ;
}
int ans = 0 ;
vector res ;
function ok = [&](int u)
{
if(res.size() == 0) return false ;
if(u == 365) return true ;
int sum = 0 ;
for(auto x : res) sum += u - x ;
return sum + res.size() >= 20 ;
} ;
for(int i = 1 ; i <= 365 ; i ++)
{
if(vis[i]) res.push_back(i) ;
if(ok(i)) res.clear() , ans ++ ;
}
cout << ans << '\n' ;
return 0 ;
}
二分答案。表示取过前个菜且送过前个菜且当前位于的最小时间。通过二分答案的最大等待时间来保证合法性。
#include
using namespace std ;
const int maxn = 1000 + 10 ;
typedef long long ll ;
int n , m ;
vector> g[maxn] ;
long long dis[maxn][maxn] ;
long long dp[maxn][maxn] ;
typedef pair pli ; //±ßȨlong long
int k ;
long long s[maxn] , u[maxn] , t[maxn] ;
struct Dij
{
long long dis[maxn] ;
priority_queue , greater > q ;
void init()
{
memset(dis , 0x3f , sizeof(dis)) ;
}
void dijkstra(int s)
{
dis[s] = 0 ;
q.push(make_pair(0 , s)) ;
while(!q.empty())
{
pli p = q.top() ;
q.pop() ;
int u = p.second ;
if(p.first != dis[u]) continue ; //ÓÅ»¯£¬²»ÓþÉÖµ¸üС£
for(auto x : g[u])
{
int v = x.first ;
long long w = x.second ;
if(dis[v] > dis[u] + w)
{
dis[v] = dis[u] + w ;
q.push(make_pair(dis[v] , v)) ;
}
}
}
}
} dij ;
bool ok(long long up)
{
//dp[i][j]±íʾÄÃÁËÇ°i¸öÎïÆ·ÇÒËÍÁËÇ°j¸öÎïÆ·£¬ÇÒµ±Ê±ÔÚu[j]µÄ×îСʱ¼ä
memset(dp , 0x3f , sizeof(dp)) ;
for(int i = 1 ; i <= k ; i ++) dp[i][0] = t[i] ;
for(int i = 1 ; i <= k ; i ++)
for(int j = 0 ; j <= i ; j ++)
{
if(dp[i][j] > 1e16) continue ;
//cout << i << ' ' << j << ' ' << dp[i][j] << '\n' ;
if(i == j)
{
long long res = dp[i][j] + dis[u[j]][1] ;
for(int p = i + 1 ; p <= k ; p ++)
{
long long cost = max(res , t[p]) + dis[1][u[j + 1]] ;
if(cost <= s[i + 1] + up)
dp[p][i + 1] = min(dp[p][i + 1] , cost) ;
}
}
else
{
long long cost = dp[i][j] + dis[u[j]][u[j + 1]] ;
if(cost < dp[i][j + 1] && cost <= s[j + 1] + up)
{
dp[i][j + 1] = cost ;
}
}
}
return dp[k][k] < 1e16 ;
}
int main()
{
std::ios::sync_with_stdio(false) , cin.tie(0) ;
cin >> n >> m ;
for(int i = 1 ; i <= m ; i ++)
{
int u , v , w ;
cin >> u >> v >> w ;
g[u].push_back({v , w}) ;
g[v].push_back({u , w}) ;
}
for(int i = 1 ; i <= n ; i ++)
{
dij.init() ;
dij.dijkstra(i) ;
for(int j = 1 ; j <= n ; j ++) dis[i][j] = dij.dis[j] ;
}
u[0] = 1 ;
cin >> k ;
for(int i = 1 ; i <= k ; i ++) cin >> s[i] >> u[i] >> t[i] ;
long long ans = 1e16 ;
long long l = 0 , r = 1e16 ;
while(l <= r)
{
long long mid = (l + r) / 2 ;
if(ok(mid)) ans = mid , r = mid - 1 ;
else l = mid + 1 ;
}
cout << ans << '\n' ;
return 0 ;
}
你有n个小兵,对手有m个小兵,告诉你每个小兵当前的hp,每一轮会随机一个小兵使其hp-1,当对手的m个小兵的血量全为0时结束,问你d轮前结束的概率
,直接状压dp的话复杂度是无法承受,容易发现顺序是无关的,所以按照hp升序后状压即可,本质不同的状态数只有300*300多
#include
#define fi first
#define se second
using namespace std;
using pii = pair;
using db = long double;
int n, m, d, hp1[5], hp2[5], dp[6][7];
int encode(int *a, int n)
{
static int b[5];
memcpy(b, a, n<<2);
sort(b, b+n);
int x = 0;
for(int i=0; i=0; i--) a[i] = x%10, x /= 10;
}
int main()
{
scanf("%d%d%d", &n, &m, &d);
for(int i=0; i cur, nxt;
cur[{encode(hp1, n), encode(hp2, m)}] = 1.0;
db ans = 0.0;
while(d--)
{
//cout << d << ' ' << cur.size() << '\n';
for(auto it : cur)
{
decode(hp1, n, it.fi.fi), decode(hp2, m, it.fi.se);
int alive = 0, cnt = 0;
for(int i=0; i0);
for(int i=0; i0), cnt += hp2[i];
if(cnt>d+1) continue;
for(int i=n-1; i>=0; i--)
{
if(hp1[i])
{
--hp1[i];
nxt[{encode(hp1, n), it.fi.se}] += it.se*(1.0/alive);
++hp1[i];
}
else break;
}
for(int i=m-1; i>=0; i--)
{
if(hp2[i])
{
--hp2[i];
int tmp = encode(hp2, m);
if(!tmp) ans += it.se*(1.0/alive);
else nxt[{it.fi.fi, tmp}] += it.se*(1.0/alive);
++hp2[i];
}
else break;
}
}
swap(nxt, cur);
nxt.clear();
}
printf("%.8Lf\n", ans);
return 0;
}
#include
using namespace std ;
int main()
{
int l , m ;
scanf("%d%d" , &l , &m) ;
vector> ans ;
int mn = 1e9 ;
getchar() ;
while(m --)
{
vector v ;
string s = "" ;
while(1)
{
char c = getchar() ;
if(c == '\n') break ;
if(c == ',')
{
v.push_back(s) ;
s = "" ;
continue ;
}
s += c ;
}
v.push_back(s) ;
//cout << v.size() << '\n' ;
assert(v.size() == 5) ;
array a ;
for(int i = 1 ; i < 5 ; i ++)
{
int now = 0 ;
for(auto u : v[i]) now = now * 10 + (u - '0') ;
a[i - 1] = now ;
}
function ok = [&]()
{
double c = a[1] ;
double t = a[2] ;
double r = a[3] ;
double res = (t + r) / (t / (l / c)) ;
return res < 10080 || fabs(res - 10080) < (1e-6) ;
} ;
if(ok()) mn = min(mn , a[0]) , ans.push_back({v[0] , a[0]}) ;
}
for(auto u : ans) if(u.second == mn) printf("%s\n" , u.first.c_str()) ;
if(ans.size() == 0) puts("no such mower") ;
return 0 ;
}
有n个物品,问你能否选择一个集合使得价值恰好为x,一个特殊性质是大的物品的价值至少是小的物品的价值的两倍
从大到小考虑每个物品,如果当前物品的价值小于等于x,则必须选,否则剩下的物品全选也到不了x。价值很大,上个python。
n, s = map(int, input().split())
p = []
for _ in range(n):
name, val = input().split()
val = int(val)
p.append((val, name))
p.sort(reverse=True)
choose = []
for item in p:
if item[0] <= s:
choose.append(item[1])
s -= item[0]
if s==0:
print(len(choose))
for x in choose:
print(x)
else:
print(0)
通过算出的个数分别是。容易发现。我们把所有的摆出来,然后把插入空隙中即可。
注意特判其中有的情况。
#include
using namespace std ;
const int maxn = 1e5 + 10 ;
int cnt[maxn] ;
int main()
{
std::ios::sync_with_stdio(false) , cin.tie(0) ;
int a , b , c , d ;
cin >> a >> b >> c >> d ;
function ok = [&](string s)
{
array f ;
f[0] = f[1] = f[2] = f[3] = 0 ;
for(int i = 0 ; i < s.size() ; i ++)
{
for(int j = i + 1 ; j < s.size() ; j ++)
if(s[i] == '0' && s[j] == '0') f[0] ++ ;
else if(s[i] == '0' && s[j] == '1') f[1] ++ ;
else if(s[i] == '1' && s[j] == '0') f[2] ++ ;
else f[3] ++ ;
}
//cout << f[0] << ' ' << f[1] << ' ' << f[2] << ' ' << f[3] << '\n' ;
return f[0] == a && f[1] == b && f[2] == c && f[3] == d ;
} ;
if(a == 0 && d == 0)
{
if(ok("0")) cout << "0\n" ;
else if(ok("01")) cout << "01\n" ;
else if(ok("10")) cout << "10\n" ;
else if(ok("1")) cout << "1\n" ;
else cout << "impossible\n" ;
return 0 ;
}
else if(a == 0)
{
int num1 = -1 ;
for(int i = 1 ; i * (i - 1) / 2 <= d ; i ++)
if(i * (i - 1) / 2 == d) num1 = i ;
if(num1 == -1 || b + c > num1 || b + c > 0 && b + c < num1)
{
cout << "impossible\n" ;
return 0 ;
}
if(b == 0 && c == 0)
{
for(int i = 1 ; i <= num1 ; i ++) cout << "1" ;
cout << '\n' ;
}
else
{
for(int i = 1 ; i <= c ; i ++) cout << "1" ;
cout << "0" ;
for(int i = 1 ; i <= b ; i ++) cout << "1" ;
}
return 0 ;
}
else if(d == 0)
{
int num0 = -1 ;
for(int i = 1 ; i * (i - 1) / 2 <= a ; i ++)
if(i * (i - 1) / 2 == a) num0 = i ;
if(num0 == -1 || b + c > num0 || b + c > 0 && b + c < num0)
{
cout << "impossible\n" ;
return 0 ;
}
if(b == 0 && c == 0)
{
for(int i = 1 ; i <= num0 ; i ++) cout << "0" ;
cout << '\n' ;
}
else
{
for(int i = 1 ; i <= b ; i ++) cout << "0" ;
cout << "1" ;
for(int i = 1 ; i <= c ; i ++) cout << "0" ;
}
return 0 ;
}
else
{
int num0 = -1 , num1 = -1 ;
for(int i = 1 ; i * (i - 1) / 2 <= a ; i ++)
if(i * (i - 1) / 2 == a) num0 = i ;
for(int i = 1 ; i * (i - 1) / 2 <= d ; i ++)
if(i * (i - 1) / 2 == d) num1 = i ;
//cout << num0 << ' ' << num1 << '\n' ;
if(num0 == -1 || num1 == -1 || num0 * num1 != b + c)
{
cout << "impossible\n" ;
return 0 ;
}
for(int i = num0 ; i >= 1 ; i --)
{
while(b >= i)
{
cnt[i] ++ ;
num1 -- ;
b -= i ;
}
}
cnt[0] = num1 ;
for(int i = 0 ; i <= num0 ; i ++)
{
if(i > 0) cout << "0" ;
for(int j = 1 ; j <= cnt[i] ; j ++) cout << "1" ;
}
cout << "\n" ;
}
return 0 ;
}
至多k的答案就是,求恰好那就套个二项式反演
#include
using namespace std;
const int N = 2505, mod = 1e9 + 7;
int n, k, dp[N];
int Pow(int a, int b)
{
int ans = 1;
while(b)
{
if(b&1) ans = 1ll*ans*a%mod;
a = 1ll*a*a%mod;
b >>= 1;
}
return ans;
}
int fac[N], ifac[N];
void init(int n)
{
fac[0] = 1;
for(int i=1; i<=n; i++) fac[i] = 1ll*fac[i-1]*i%mod;
ifac[n] = Pow(fac[n], mod-2);
for(int i=n-1; i>=0; i--) ifac[i] = 1ll*ifac[i+1]*(i+1)%mod;
}
int C(int a, int b)
{
if(a