A
贪心,最小的n个数肯定分在每个组用来垫,然后从小到大考虑,对于每个数肯定尽量让他成为某组最大的,这样后面比他大的数就有更多成为次大的,肯定比让他成为次大的更优,所以答案就是排序后第n+1,n+3,n+5…3n-1项的和
B
倒着处理询问,变成每次将距离点v<=d的所有点中无色的点染色,对每个点记录v[x][d]表示离这个点距离<=d的点是否都被染色,复杂度
O(nd)
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn = 110000;
const int maxk = 12;
int n,m,Q;
int col[maxn];
struct edge{int y,nex;}a[maxn<<1]; int len,fir[maxn];
inline void ins(const int x,const int y){a[++len]=(edge){y,fir[x]};fir[x]=len;}
int e[maxn][3];
bool v[maxn][maxk];
struct node{int x,p;};
queue<node>q;
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int x,y; scanf("%d%d",&x,&y);
ins(x,y); ins(y,x);
}
scanf("%d",&Q);
for(int i=1;i<=Q;i++) scanf("%d%d%d",&e[i][0],&e[i][1],&e[i][2]);
for(int i=Q;i>=1;i--)
{
int cc=e[i][2];
q.push((node){e[i][0],e[i][1]});
while(!q.empty())
{
const node now=q.front(); q.pop();
if(v[now.x][now.p]) continue;
if(!col[now.x]) col[now.x]=cc;
for(int j=now.p;j>=0&&!v[now.x][j];j--) v[now.x][j]=true;
if(now.p==0) continue;
for(int k=fir[now.x],y=a[k].y;k;k=a[k].nex,y=a[k].y)
q.push((node){y,now.p-1});
}
}
for(int i=1;i<=n;i++) printf("%d\n",col[i]);
return 0;
}
C
蜜汁构造
考虑一个1~k的排列+1~k的序列,他的形如TT的子序列就是该排列上升子的数量
将空集也定义成上升子后,在一个1~k的排列后加k+1,其上升子数量*2
在其前面加上k+1,上升子数量+1
就可以倍增得到N+1个上升子的1~k的排列了
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn = 210;
ll n;
int t[maxn],tp;
int q[maxn],head,tail;
int main()
{
scanf("%lld",&n); ++n;
while(n) t[++tp]=n&1,n>>=1;
int k=1; q[head=tail=100]=k;
for(int i=tp-1;i>=1;i--)
{
if(t[i]) q[--head]=++k;
if(i>1) q[++tail]=++k;
}
printf("%d\n",(tail-head+1)*2);
for(int i=head;i<=tail;i++) printf("%d ",q[i]);
for(int i=1;i<=k;i++) printf("%d ",i);
return 0;
}
D
对于同色的球,排序后,若wi(i>1)+w1<=X,则wi可以视为w1(和他换相当于和w1换)
对于不同色的球,找出所有颜色的球的w1最小和次小的2种颜色c1,c2
对于除了c1的其他颜色,这些球若
+wc1[1]<=Y
,则他们也是可以自由活动的,否则只能固定在原位不动,相当于没有
对于c1色的球,除了用
wc1[1]
同色更新,要用
wc2[1]
异色尝试更新自由活动的球集合,找出所有自由活动的球后,就是一个有相同元素的排列数
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn = 210000;
const ll Mod = 1e9+7;
ll inv[maxn],s[maxn];
void pre()
{
s[0]=1ll; for(int i=1;i<maxn;i++) s[i]=s[i-1]*(ll)i%Mod;
inv[0]=inv[1]=1;
for(ll i=2;i<maxn;i++)
inv[i]=(-(Mod/i)*inv[Mod%i]%Mod+Mod)%Mod;
for(int i=1;i<maxn;i++) inv[i]=inv[i]*inv[i-1]%Mod;
}
int n,X,Y;
vector<int>V[maxn];
int main()
{
pre();
scanf("%d%d%d",&n,&X,&Y);
for(int i=1;i<=n;i++)
{
int w,c; scanf("%d%d",&c,&w);
V[c].push_back(w);
}
for(int i=1;i<=n;i++) sort(V[i].begin(),V[i].end());
int m1=0,m2=0;
for(int i=1;i<=n;i++) if(V[i].size())
{
for(int j=1;j<V[i].size();j++) if(V[i][j]+V[i][0]<=X) V[i][j]=V[i][0];
if(!m1||V[m1][0]>V[i][0]) m2=m1,m1=i;
else if(!m2||V[m2][0]>V[i][0]) m2=i;
}
if(!m2) return puts("1"),0;
int ren=1; ll ans=1ll;
for(int j=1;j<V[m1].size();j++)
if(V[m1][j]+V[m1][0]<=X||V[m1][j]+V[m2][0]<=Y) ren++;
ans=ans*inv[ren]%Mod;
for(int i=1;i<=n;i++) if(i!=m1)
{
int now=0;
for(int j=0;j<V[i].size();j++) if(V[m1][0]+V[i][j]<=Y) now++;
ans=ans*inv[now]%Mod;
ren+=now;
}
ans=ans*s[ren]%Mod;
printf("%lld\n",ans);
return 0;
}
E
若骆驼不跳跃,则他肯定往两边遍历所有他能走到的点,将1~n划分为若干个内部互相可达的区间
注意到骆驼最多跳跃logV次,相当于有logV层,每层有若干条不相交、覆盖该层的线段,然后对于最大的一层d,询问对于每个线段,在0~d-1层每层挑一个线段,加上这个线段是否能覆盖1~n
因为d=logV很小,可以状压f[i]表示i状态的这些层最多覆盖1~f[i],g[i]表示最多从n覆盖到n~g[i],再做一个整合的dp
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
inline void up(int &x,const int &y){if(x<y)x=y;}
inline void down(int &x,const int &y){if(x>y)x=y;}
const int maxn = 210000;
const int maxd = 20;
const int maxv = 810000;
int n,V,d,t[maxn];
int p[maxn];
int li[maxn*maxd],ri[maxn*maxd],cnt,bel[maxd][maxn];
int f[maxv],g[maxv];
int dp[maxn];
int main()
{
scanf("%d%d",&n,&V);
for(int i=1;i<=n;i++) scanf("%d",&p[i]);
d=0; for(int now=V;now;now>>=1) t[++d]=now; t[++d]=0;
for(int i=1;i*2<=d;i++) swap(t[i],t[d-i+1]);
for(int i=1;i<=d;i++)
{
int cc=t[i]; int now=cnt;
bel[i][1]=++cnt;
li[cnt]=ri[cnt]=1;
for(int j=2;j<=n;j++)
{
if(p[j]-p[j-1]<=cc) ri[bel[i][j]=bel[i][j-1]]=j;
else li[bel[i][j]=++cnt]=ri[cnt]=j;
}
}
int al=1<<d-1;
memset(f,-1,sizeof f); f[0]=0;
for(int i=0;i<al;i++) if(f[i]!=-1)
{
if(f[i]==n)
{
for(int j=0;j<d-1;j++) if(!(i>>j&1))
up(f[i+(1<<j)],f[i]);
}
else
{
for(int j=0;j<d-1;j++) if(!(i>>j&1))
up(f[i+(1<<j)],ri[bel[j+1][f[i]+1]]);
}
}
for(int i=0;i<al;i++) g[i]=n+1;
for(int i=0;i<al;i++)
{
if(g[i]==1)
{
for(int j=0;j<d-1;j++) if(!(i>>j&1))
down(g[i+(1<<j)],g[i]);
}
else
{
for(int j=0;j<d-1;j++) if(!(i>>j&1))
down(g[i+(1<<j)],li[bel[j+1][g[i]-1]]);
}
}
for(int i=0;i<=n;i++) dp[i]=n+1;
for(int i=0;i<al;i++) down(dp[f[i]],g[al-1-i]);
for(int i=n-1;i>=0;i--) down(dp[i],dp[i+1]);
for(int i=1;i<=n;i++)
{
int l=li[bel[d][i]],r=ri[bel[d][i]];
if((r==n&&f[al-1]>=l-1)||(r<n&&dp[l-1]<=r+1)) puts("Possible");
else puts("Impossible");
}
return 0;
}
F
主要证明2个充要性质:
b[i]在a[i]~a[n-i+1];
对于任意j< i,不存在b[j]在b[i]和b[i+1]之间
(我其实还是有点晕qwq就不在这里证了)
然后可以倒着dp,f[i][j][k]表示dp到n-i+1轮,可选的数有j个,这一轮选的数在其中排第k的方案数,枚举上一轮b[i]在其中的排名,由于性质,中间夹的数要删掉,不可能在之前的b[j]出现
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn = 110;
const int Mod = 1e9+7;
int n,m;
int a[maxn];
int f[maxn][maxn][maxn];
void add(int &x,int y){ x+=y; if(x>=Mod)x-=Mod; }
int main()
{
scanf("%d",&n); m=2*n-1;
for(int i=1;i<=m;i++) scanf("%d",&a[i]);
sort(a+1,a+m+1);
f[1][1][1]=1;
for(int k=1;k<n;k++)
{
for(int i=1;i<=m;i++) for(int j=1;j<=i;j++) if(f[k][i][j])
{
int tmp=f[k][i][j];
int now=j,al=i;
if(a[n-k]!=a[n-k+1]) al++,now++;
if(a[n+k]!=a[n+k-1]) al++;
add(f[k+1][al][now],tmp);
for(int l=1;l<now;l++) add(f[k+1][al-(now-l-1)][l],tmp);
for(int l=now+1;l<=al;l++) add(f[k+1][al-(l-now-1)][now+1],tmp);
}
}
int re=0;
for(int i=1;i<=m;i++) for(int j=1;j<=i;j++) add(re,f[n][i][j]);
printf("%d\n",re);
return 0;
}