B
先两边贪心,然后中间部分卷积
#pragma GCC optimize("O3")
#include<iostream>
#include<string.h>
#include<algorithm>
#include<deque>
#include<assert.h>
#define lint int64_t
#define mod1 998244353ll
#define mod2 1004535809ll
#define g 3ll
#define invg1 332748118ll
#define invg2 334845270ll
#define maxn 400005
using
namespace
std;
int n;
lint a[maxn],b[maxn];
int p1,p2,sz,limit;
lint kotaemax[maxn],kotaemin[maxn];
lint qow(lint a,lint b,lint mod){
lint ans=1;
for(;b;a=a*a%mod,b>>=1) if(b&1) ans=ans*a%mod;
return ans;
}
lint L,R[maxn];
lint A1[maxn],B1[maxn];
lint A2[maxn],B2[maxn];
void NTT(lint A[],lint mod,lint G){
for(int i=0;i<limit;i++){
if(i<R[i]){
swap(A[i],A[R[i]]);
}
}
for(int mid=1;mid<limit;mid<<=1){
lint w1=qow(G,(mod-1)/(mid<<1),mod);
for(int j=0;j<limit;j+=(mid<<1)){
lint wi=1;
for(int k=0;k<mid;k++,wi=wi*w1%mod){
lint U=A[j+k],V=wi*A[j+k+mid]%mod;
A[j+k]=(U+V)%mod;
A[j+k+mid]=(U-V+mod)%mod;
}
}
}
if(G>3){
lint invbase=qow(limit,mod-2,mod);
for(int i=0;i<limit;i++){
A[i]=A[i]*invbase%mod;
}
}
}
lint comb(lint u,lint v){
/*
ans=k1*m1+u
ans=k2*m2+v
k1*m1+u-v=k2*m2
k1*m1+u-v=0 modm2
k1=(v-u)/m1 modm2
*/
lint k1=(v-u+mod2)%mod2*qow(mod1,mod2-2,mod2)%mod2;
return k1*mod1+u;
}
deque<lint> tem;
void slv_min(){
//sort(a,a+n);
//sort(b,b+n);
p1=lower_bound(a,a+n,0)-a;
p2=lower_bound(b,b+n,0)-b;
tem.clear();
for(int i=0;i<min(p1,n-p2);i++){
tem.push_back(a[i]*b[n-i-1]);
}
for(int i=0;i<min(n-p1,p2);i++){
tem.push_back(a[n-i-1]*b[i]);
}
sort(tem.begin(),tem.end(),[&](lint u,lint v){
return u<v;
});
lint s=0;
for(int i=0;i<tem.size();i++){
s+=tem[i];
kotaemin[i+1]=s;
}
/*
cal L, R, limit
*/
sz=abs(n-p1-p2);
limit=1;
L=0;
while(limit<=(sz<<1)){
limit<<=1;
L++;
}
for(int i=0;i<limit;i++){
R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));
}
memset(A1,0,limit*sizeof(lint));
memset(A2,0,limit*sizeof(lint));
memset(B1,0,limit*sizeof(lint));
memset(B2,0,limit*sizeof(lint));
// memset(A1,0,sizeof(A1));
// memset(A2,0,sizeof(A2));
// memset(B1,0,sizeof(B1));
// memset(B2,0,sizeof(B2));
int sta=min(p1,n-p2),stb=min(n-p1,p2);
for(int i=0;i<sz;i++){
A1[i]=A2[i]=abs(a[sta+i]);
B1[i]=B2[i]=abs(b[stb+i]);
}
if(p1+p2>n){
reverse(A1,A1+sz);
reverse(A2,A2+sz);
reverse(B1,B1+sz);
reverse(B2,B2+sz);
}
NTT(A1,mod1,g);
NTT(A2,mod2,g);
NTT(B1,mod1,g);
NTT(B2,mod2,g);
for(int i=0;i<limit;i++){
A1[i]=A1[i]*B1[i]%mod1;
A2[i]=A2[i]*B2[i]%mod2;
}
NTT(A1,mod1,invg1);
NTT(A2,mod2,invg2);
for(int i=0;i<sz;i++){
kotaemin[tem.size()+i+1]=s+comb(A1[i],A2[i]);
}
}
void slv_max(){
sort(a,a+n);
sort(b,b+n);
p1=lower_bound(a,a+n,0)-a;
p2=lower_bound(b,b+n,0)-b;
bool inverseA=p1>p2;
if(p1>p2){
swap(p1,p2);
}
tem.clear();
for(int i=0;i<p1;i++){
tem.push_back(a[i]*b[i]);
}
for(int i=p2;i<n;i++){
tem.push_back(a[i]*b[i]);
}
sort(tem.begin(),tem.end(),[&](lint u,lint v){
return u>v;
});
lint s=0;
for(int i=0;i<tem.size();i++){
s+=tem[i];
kotaemax[i+1]=s;
}
/*
cal L, R, limit
*/
sz=p2-p1;
limit=1;
L=0;
while(limit<=(sz<<1)){
limit<<=1;
L++;
}
for(int i=0;i<limit;i++){
R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));
}
memset(A1,0,limit*sizeof(lint));
memset(A2,0,limit*sizeof(lint));
memset(B1,0,limit*sizeof(lint));
memset(B2,0,limit*sizeof(lint));
// memset(A1,0,sizeof(A1));
// memset(A2,0,sizeof(A2));
// memset(B1,0,sizeof(B1));
// memset(B2,0,sizeof(B2));
if(inverseA){
for(int i=p1;i<p2;i++){
A1[p2-i-1]=A2[p2-i-1]=abs(a[i]);
B1[i-p1]=B2[i-p1]=abs(b[i]);
}
}
else{
for(int i=p1;i<p2;i++){
A1[i-p1]=A2[i-p1]=abs(a[i]);
B1[p2-i-1]=B2[p2-i-1]=abs(b[i]);
}
}
NTT(A1,mod1,g);
NTT(A2,mod2,g);
NTT(B1,mod1,g);
NTT(B2,mod2,g);
for(int i=0;i<limit;i++){
A1[i]=A1[i]*B1[i]%mod1;
A2[i]=A2[i]*B2[i]%mod2;
}
NTT(A1,mod1,invg1);
NTT(A2,mod2,invg2);
for(int i=0;i<sz;i++){
kotaemax[tem.size()+i+1]=s-comb(A1[i],A2[i]);
}
}
signed main(){
scanf("%lld",&n);
//freopen("B.txt","w",stdout);
//n=100000;
for(int i=0;i<n;i++){
scanf("%lld",&a[i]);
//a[i]=i&1?0:-10000;
}
for(int i=0;i<n;i++){
scanf("%lld",&b[i]);
//b[i]=i&1?0:10000;
}
slv_max();
slv_min();
for(int i=1;i<=n;i++){
printf("%lld %lld\n",kotaemin[i],kotaemax[i]);
}
end:
return EOF+1;
}
/*
4
-3 -4 5 -9
-10 -6 -7 -3
-50 90
-41 118
-20 136
22 121
6
6 -1 -2 -8 -1 -9
-10 -10 2 7 -9 -10
-63 90
-123 170
-139 212
-130 232
-120 241
-101 239
*/
F
贪心求点n-1所在连通块最多能有多少(除去点n)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define mod 1000000007
#define pb push_back
typedef pair<int,int> pir;
string sstr[]={"NO\n","YES\n"};
const int N=300010;
int T,n,m;
int vis[N];
vector<int> vec[N];
void dfs(int x)
{
vis[x]=1;
for(auto j:vec[x]){
if(vis[j]) continue;
if(j==n) continue;
dfs(j);
}
}
signed main()
{
cin>>n>>m;
for(int i=1;i<=m;i++){
int u,v;
cin>>u>>v;
vec[u].pb(v);
vec[v].pb(u);
}
dfs(n-1);
for(int i=1;i<=n;i++){
if(vis[i]) cout<<'B';
else cout<<'A';
}
}
H
费用流,偶数点位置确定,考虑奇数点插入偶数点的代价,尽量小且每个位置插入1个即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f3f3f3f3f
#define mod 1000000007
typedef pair<ll,int> pir;
string sstr[]={"No\n","Yes\n"};
const int N=200010;
int n,m,s,t,cnt=1;//从2开始,保证相反边只有低位不同
int to[N],nxt[N],head[N],pre[N],prep[N],gnum;//pre:维护路径前置节点,prep:维护链接的边的编号
ll wei[N],dis[N],cost[N],h[N],totf,totc;//h维护势
void add(int u,int v,ll w,ll c)
{
to[++cnt]=v;
wei[cnt]=w;
nxt[cnt]=head[u];
head[u]=cnt;
cost[cnt]=c;
//反向边
to[++cnt]=u;
wei[cnt]=0;
nxt[cnt]=head[v];
head[v]=cnt;
cost[cnt]=-c;
}
void Dijkstra()
{
for(int i=0;i<=gnum;i++) dis[i]=inf;
static priority_queue<pir, vector<pir>, greater<pir> > q;
while(!q.empty()) q.pop();
dis[s]=0;
q.push(pir(dis[s],s));
while(!q.empty()){
pir tmp=q.top();
q.pop();
int u=tmp.second;
if(dis[u]<tmp.first) continue;//最大费用的话改变符号
for(int i=head[u];i;i=nxt[i]){
int v=to[i];
if(wei[i]<=0) continue;//流量用完
if(dis[v]==inf||dis[v]>dis[u]+cost[i]+h[u]-h[v]){ //最大费用的话改变符号
dis[v]=dis[u]+cost[i]+h[u]-h[v];
pre[v]=u;prep[v]=i;
q.push(pir(dis[v],v));
}
}
}
}
pair<ll,ll> solve()
{
while(1){
Dijkstra();
if(dis[t]==inf) break;
for(int i=1;i<=gnum;i++) h[i]+=(dis[i]!=inf)? dis[i]:0;
ll cf=inf;//当前增广路的花费和流量
for(int i=t;i!=s;i=pre[i]) cf=min(cf,wei[prep[i]]);
totf+=cf;
totc+=h[t]*cf;
assert(totc>=0);
for(int i=t;i!=s;i=pre[i]){
wei[prep[i]]-=cf;//正向边
wei[prep[i]^1]+=cf;//反向边
}
}
return pair<ll,ll>(totf,totc);
}
void init()
{
cnt=1;
totc=totf=0;
for(int i=0;i<=gnum;i++) head[i]=h[i]=0;
}
int g[510][510];
signed main()
{
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>g[i][j];
}
}
s=n+3,t=n+4;
gnum=n+5;
init();
for(int i=1;i<=n;i+=2) add(s,i,1,0);
//2
add(2,t,1,0);
for(int i=1;i<=n;i+=2){
if(g[i][2]!=0) add(i,2,1,g[i][2]);
}
for(int i=4;i<=n;i+=2){//枚举连接i,i-2的点
add(i,t,1,0);
for(int j=1;j<=n;j+=2){
if(g[j][i]!=0&&g[j][i-2]!=0){
add(j,i,1,g[j][i]+g[j][i-2]);
}
}
}
if(n%2){//奇数,最后还需要一个单独的n-1
add(n+1,t,1,0);
for(int j=1;j<=n;j+=2){
if(g[j][n-1]!=0) add(j,n+1,1,g[j][n-1]);
}
}
auto tmp=solve();
cout<<tmp.second<<'\n';
}
I
模拟
#include<iostream>
#include<map>
#define maxn 200005
using
namespace
std;
map<string,int> s2i;
string s;
int n,st;
int a;
int check(){
if(a==0){
if(st==3) return 32;
if(st==4) return 31;
return 30;
}
int now=(1861913578+st-a)%7;
switch(now){
case 0:{
a%=91;
if(a>=60){
a-=60;
now=4;
}
else if(a>=30){
a-=30;
now=2;
}
break;
}
case 1:{
if(a>=62){
a-=62;
now=0;
a%=91;
if(a>=60){
a-=60;
now=4;
}
else if(a>=30){
a-=30;
now=2;
}
}
if(a>=30){
a-=30;
now=3;
}
break;
}
case 2:{
a%=91;
if(a>=61){
a-=61;
now=0;
}
else if(a>=30){
a-=30;
now=4;
}
break;
}
case 3:{
if(a>=32){
a-=32;
now=0;
a%=91;
if(a>=60){
a-=60;
now=4;
}
else if(a>=30){
a-=30;
now=2;
}
}
break;
}
case 4:{
a%=91;
if(a>=61){
a-=61;
now=2;
}
else if(a>=31){
a-=31;
now=0;
}
break;
}
default:{
printf("ERROR\n");
break;
}
}
if(a==0){
if(st==5) return 2;
if(st==6) return 1;
return 0;
}
int ans;
if(now==3){
ans=32-a;
}
else if(now==4){
ans=31-a;
}
else{
ans=30-a;
}
return ans;
}
signed main(){
s2i["Mon"]=0;
s2i["Tue"]=1;
s2i["Wed"]=2;
s2i["Thu"]=3;
s2i["Fri"]=4;
s2i["Sat"]=5;
s2i["Sun"]=6;
cin>>s>>n;
st=s2i[s];
int kotae=1e9;
for(int i=1;i<=n;i++){
cin>>a;
kotae=min(kotae,check());
}
printf("%d\n",kotae);
}
/*
Thu 1
30
*/
J
只有两点全部在边界的点对才会有可能卡住。顺序遍历边界上的点,用栈判断能否匹配即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define mod 1000000007
#define pb push_back
typedef pair<int,int> pir;
string sstr[]={"NO\n","YES\n"};
const int N=200010;
int T,h,w,n,m;
vector<pir> up;
vector<pir> ri;
vector<pir> dw;
vector<pir> le;
vector<int> vec;
int stk[N];
int top=-1;
int cnt=0;
bool check(int x,int y)
{
if(x==0||y==0||x==h||y==w) return 1;
return 0;
}
void add(int x,int y)
{
if(x==0) up.pb(pir(y,cnt));
else if(x==h) dw.pb(pir(y,cnt));
else if(y==0) le.pb(pir(x,cnt));
else ri.pb(pir(x,cnt));
}
signed main()
{
cin>>h>>w>>n;
for(int i=1;i<=n;i++){
int a1,b1,a2,b2;
cin>>a1>>b1>>a2>>b2;
if(check(a1,b1)&&check(a2,b2)){
cnt++;
add(a1,b1);
add(a2,b2);
}
}
sort(up.begin(),up.end());
sort(dw.begin(),dw.end());
sort(le.begin(),le.end());
sort(ri.begin(),ri.end());
for(auto it:up) vec.pb(it.second);
for(auto it:ri) vec.pb(it.second);
for(int i=dw.size()-1;i>=0;i--) vec.pb(dw[i].second);
for(int i=le.size()-1;i>=0;i--) vec.pb(le[i].second);
assert(vec.size()%2==0);
for(int i=0;i<vec.size();i++){
if(top>=0&&vec[i]==stk[top]) top--;
else stk[++top]=vec[i];
}
if(top==-1) cout<<"Y\n";
else cout<<"N\n";
}
K
签到
#include <iostream>
#include <map>
#include <vector>
std::map<char, int> mp;
std::string ss[1000006];
int main()
{
std::ios::sync_with_stdio(false);
// std::cin.tie(0);
int t;
std::cin >> t;
std::string s;
for (int i = 1; i<=t; ++i) {
std::cin >> ss[i];
mp[ss[i][0]]++;
}
for (int i = 1; i<=t; ++i) {
bool flag = 1;
for (char &j:ss[i]) {
if (mp[j]<=0) {
flag = 0;
}
}
if (flag) {
std::cout << "Y";return 0;
}
}
std::cout << "N";
return 0;
}
L
按照上车顺序,定义三类人的数量为
a
,
b
,
c
a,b,c
a,b,c
枚举第一类人上车之后的状态,只需要确定座位对上坐了2个人的对数,那么座位对上1个人的数量和0个人的的数量。钦定坐了两个人的对数为x,则有概率
p
(
x
)
=
C
n
x
∗
C
n
−
x
a
−
2
∗
x
∗
2
a
−
2
∗
x
/
C
2
∗
n
a
p(x)=C_n^x*C_{n-x}^{a-2*x}*2^{a-2*x}/C_{2*n}^a
p(x)=Cnx∗Cn−xa−2∗x∗2a−2∗x/C2∗na
那么后面的
b
,
c
b,c
b,c类人的行为是确定的,分类讨论求贡献即可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define int ll
#define inf 0x3f3f3f3f
#define mod 1000000007
#define pb push_back
ll qow(ll a,ll p) {ll ans=1;for(;p;a=a*a%mod,p>>=1) if(p&1) ans=ans*a%mod;return ans;}
ll inv(ll a) {return qow(a,mod-2);}
const int N=2000010;
int T,n,a,b,c;
int ans;
int fac[N],invfac[N];
int C(int x,int y)
{
if(x<0||y<0||y>x) return 0;
return fac[x]*invfac[y]%mod*invfac[x-y]%mod;
}
int cal(int x)
{
int a1=a,b1=b,c1=c;
int ret=C(n,x)*C(n-x,a1-2*x)%mod*qow(2,a1-2*x)%mod*inv(C(2*n,a1))%mod;//概率
int bo=x;//两个均被占
int si=a1-2*x;//单个座位
int tot=a1;//贡献
if(si>=b1){
tot+=b1;
bo+=b1,si-=b1;
//剩下的是1
if(c1<=n-si-bo) tot+=c1;
else{
c1-=(n-si-bo),tot+=n-si-bo;
if(c1<=si) ;
else{
c1-=si;
c1=min(c1,n-si-bo);
tot-=c1;//原来c满意,现在不满意了
}
}
}
else{
//先跟a匹配
tot+=si,b1-=si,bo+=si,si=0;
//然后自己匹配
tot+=b1/2*2,bo+=b1/2,si=b1%2;
if(c1<=n-si-bo) tot+=c1;
else{
c1-=n-si-bo,tot+=n-si-bo;
if(c1<=si) tot+=c1;//c不满意,但是b满意了
else{
c1-=si;
tot+=si;//b满意了
c1=min(c1,n-si-bo);
tot-=c1;
}
}
}
//cout<<"|||"<<x<<' '<<ret<<' '<<tot<<'\n';
return ret*tot%mod;
}
signed main()
{
fac[0]=invfac[0]=1;
for(int i=1;i<N;i++) fac[i]=fac[i-1]*i%mod,invfac[i]=inv(fac[i]);
cin>>n>>a>>c>>b;
if(a+b>=2*n){
cout<<2*n<<'\n';
return 0;
}
for(int i=0;i<=a/2;i++){//枚举有几个成对的
if(i+a-2*i>n) continue;
ans=(ans+cal(i))%mod;
}
int tot=0;
for(int i=0;i<=a/2;i++){
if(i+a-2*i>n) continue;
tot=(tot+C(n,i)*C(n-i,a-2*i)%mod*qow(2,a-2*i)%mod*inv(C(2*n,a))%mod)%mod;
}
assert(tot==1);
cout<<ans<<'\n';
}
/*
11 10 15 6
10 5 13 11
*/
M
首先,根据d排序,验证是否可能。
然后贪心,考虑将某个数i放到最前面是否可能,剩下的数仍然根据d排序,因此维护前缀每个位置还能推迟的最大值
d
i
−
∑
j
=
1
i
t
j
d_i-\sum_{j=1}^i t_j
di−∑j=1itj的前缀最小值验证即可。选取最小可能的值放在最前面,并暴力 更新最小值。
#include <iostream>
#include <algorithm>
#define ls (node << 1)
#define rs (node << 1|1)
using ll = long long;
// #define int ll
struct Node {
int l, r;
ll mn, add;
}tree[5005*4];
struct RW{
int t, d, i;
}allrw[5005];
ll nums[5005];
int pos[5005];
int ans[5005];
bool used[5005];
ll pre_mn[5005];
signed main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
int n, d;
std::cin >>n;
for (int i = 1; i<=n; ++i) std::cin >> allrw[i].t >> allrw[i].d, allrw[i].i = i;
std::sort(allrw+1, allrw+1+n, [&](RW r1, RW r2) {
return r1.d<r2.d;
});
for (int i = 1; i<=n; ++i) {
nums[i] = nums[i-1]+allrw[i].t;
pos[allrw[i].i] = i;
if (nums[i]>allrw[i].d) {
std::cout << "*\n";
return 0;
}
}
pre_mn[0] = 1e18;
for (int i = 1; i<=n; ++i) {
nums[i]=allrw[i].d-nums[i];
pre_mn[i] = std::min(pre_mn[i-1], nums[i]);
}
// build(1, 1, n);
for (int i = 1, j = 1; i<=n; ++i) {
bool flag = 0;
for (int k = 1; k<=n; ++k) {
if (used[k]) continue;
int now = pos[k];
if (pre_mn[now-1]>=allrw[now].t) {
flag = 1;
ans[i] = k;
used[k] = 1;
nums[now] = 1e18;
break;
}
}
if (flag) {
for (int k = 1; k<=n; ++k) {
if (k<pos[ans[i]]) {
if (nums[k]<1e18)
nums[k]-= allrw[pos[ans[i]]].t;
}
pre_mn[k] = std::min(pre_mn[k-1], nums[k]);
}
}
if (!flag) {
while (used[allrw[j].i]) ++j;
used[allrw[j].i] = 1;
ans[i] = allrw[j].i;
}
}
for (int i = 1; i<=n; ++i) {
std::cout << ans[i] << " ";
}
return 0;
}