我们刚刚知道那些题的解法-7
ZR2423
一个第一次见到的套路:我们考虑转化一下两个儿子都走这个选择,我们可以考虑建第三个儿子,它的子树中的每个节点的权值等于之前两个儿子对应权值的异或和,则显然,如果接下来没有选择两个儿子都走的话,走第三个儿子正确性是显然的,如果又选择了两个儿子都走,那么就可以对于某个节点再建第三个儿子。
综上,我们可以把二叉树扩展成三叉树,这样第三个选择就变成了走第三个儿子,DP 算出
#include<bits/stdc++.h>
#define mset(a,b) memset((a),(b),sizeof((a)))
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
#define dec(i,l,r) for(int i=(r);i>=(l);i--)
#define cmax(a,b) (((a)<(b))?(a=b):(a))
#define cmin(a,b) (((a)>(b))?(a=b):(a))
#define Next(k) for(int x=head[k];x;x=li[x].next)
#define vc vector
#define ar array
#define pi pair
#define fi first
#define se second
#define mp make_pair
#define pb emplace_back
#define N 20000010
#define M number
using namespace std;
typedef double dd;
typedef long double ld;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
//#define int long long
typedef pair<int,int> P;
typedef vector<int> vi;
const int INF=0x3f3f3f3f;
const dd eps=1e-9;
template<typename T> inline void read(T &x) {
x=0; int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
x*=f;
}
int ch[N][3],ans[N][2],n,a[N],rt,tot;
bool vis[N];
inline void add(int x,int y,int z){
a[z]=a[x]^a[y];
if(!ch[x][0]) return;
ch[z][0]=++tot;ch[z][1]=++tot;
add(ch[x][0],ch[y][0],ch[z][0]);
add(ch[x][1],ch[y][1],ch[z][1]);
}
inline void build(int k){
ch[k][2]=++tot;
add(ch[k][0],ch[k][1],ch[k][2]);
if(!ch[k][0]) return;
build(ch[k][0]);build(ch[k][1]);build(ch[k][2]);
}
inline void dfs(int k){
if(!ch[k][0]){
if(a[k]) ans[k][1]=1;
else ans[k][0]=1;
return;
}
dfs(ch[k][0]);dfs(ch[k][1]);dfs(ch[k][2]);
rep(i,0,2) ans[k][0]|=(ans[ch[k][i]][1]==0);
rep(i,0,2) ans[k][1]|=(ans[ch[k][i]][0]==0);
if(a[k]) swap(ans[k][0],ans[k][1]);
}
int main(){
// freopen("my.in","r",stdin);
// freopen("my.out","w",stdout);
read(n);tot=n;
rep(i,1,n){
int l,r,c;read(l);read(r);read(c);
vis[l]=vis[r]=1;a[i]=c;
ch[i][0]=l;ch[i][1]=r;
}
rep(i,1,n) if(!vis[i]){rt=i;break;}
build(rt);dfs(rt);
rep(i,1,n){
if(ans[i][0]) puts("Alice");
else puts("Bob");
}
}
ZR2438
考虑
我们在最前面放一个
#include<bits/stdc++.h>
#define mset(a,b) memset((a),(b),sizeof((a)))
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
#define dec(i,l,r) for(int i=(r);i>=(l);i--)
#define cmax(a,b) (((a)<(b))?(a=b):(a))
#define cmin(a,b) (((a)>(b))?(a=b):(a))
#define Next(k) for(int x=head[k];x;x=li[x].next)
#define vc vector
#define ar array
#define pi pair
#define fi first
#define se second
#define mp make_pair
#define pb emplace_back
#define N number
#define M number
using namespace std;
typedef double dd;
typedef long double ld;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
//#define int long long
typedef pair<int,int> P;
typedef vector<int> vi;
const int INF=0x3f3f3f3f;
const dd eps=1e-9;
template<typename T> inline void read(T &x) {
x=0; int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
x*=f;
}
int t,n,Q;
int main(){
read(t);
while(t--){
read(n);read(Q);
int m=(1+(1+(Q-1)*3))*Q/2;
if(n<m){puts("-1");continue;}
if(Q==1){
rep(i,1,n) putchar('a');
puts("");
continue;
}
rep(i,m+1,n) putchar('a');
rep(i,1,Q-1){
dec(j,0,i-1) putchar('a'+j);
dec(j,0,i-1) putchar('a'+j);
}
putchar('a'+Q-1);
dec(j,0,Q-2) putchar('a'+j);
dec(i,1,Q-1){
dec(j,0,i-1) putchar('a'+j);
}
puts("");
}
return 0;
}
ZR2440
考虑一个 DP,设 dfs(k,v1,v2,s)
表示目前填到了
转移的话暴力枚举下一个数填在哪里即可。
为什么?因为其实所有合法的状态是在可接受范围内。首先填完
#include<bits/stdc++.h>
#define mset(a,b) memset((a),(b),sizeof((a)))
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
#define dec(i,l,r) for(int i=(r);i>=(l);i--)
#define cmax(a,b) (((a)<(b))?(a=b):(a))
#define cmin(a,b) (((a)>(b))?(a=b):(a))
#define Next(k) for(int x=head[k];x;x=li[x].next)
#define vc vector
#define ar array
#define pi pair
#define fi first
#define se second
#define mp make_pair
#define pb emplace_back
#define N 61
#define M number
using namespace std;
typedef double dd;
typedef long double ld;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
#define int long long
typedef pair<int,int> P;
typedef vector<int> vi;
const int INF=0x3f3f3f3f;
const dd eps=1e-9;
const int mod=1e9+7;
template<typename T> inline void read(T &x) {
x=0; int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
x*=f;
}
int n;
vi e[N];
bool vis[N];
unordered_map<int,int> f[N][N][N];
inline bool Dfs(int s,int k,int fat){
for(int to:e[k]){
if(to==fat||vis[to]==1) continue;
if(!Dfs(s,to,k)) return 0;
if(fat!=0){
if(((s>>(to-1))&1)!=((s>>(k-1))&1)) return 0;
}
}
return 1;
}
inline bool chk(int s,int a,int b){
vis[a]=1;vis[b]=1;
if(!Dfs(s,a,0)){
// printf("a=%d BAN\n",a);
return 0;
}
if(!Dfs(s,b,0)){
// printf("b=%d BAN\n",b);
return 0;
}
vis[a]=0;vis[b]=0;
return 1;
}
//v1 is k, v2 is k-1
//s is used
inline int dfs(int k,int v1,int v2,int s){
// printf("Enter: k=%d v1=%d v2=%d s=%d\n",k,v1,v2,s);
if(k==n){
// printf("k=%d\n",k);
return 1;
}
// puts("Here");
if(f[k][v1][v2].find(s)!=f[k][v1][v2].end()) return f[k][v1][v2][s];
// puts("Here");
// f[k][v1][v2][s]=0;
int &ans=f[k][v1][v2][s];
ans=0;
// puts("Here");
if(v1&&v2&&!chk(s,v1,v2)){
ans=0;
// printf("chk no k=%d v1=%d v2=%d s=%d\n",k,v1,v2,s);
return 0;
}
// puts("Here");
if(v2==0){
rep(i,0,n-1){
if((s>>i)&1) continue;
int nw=i+1;
ans=(ans+dfs(k+1,nw,v1,s|(1ll<<i)))%mod;
}
}
else{
int cnt=0,id=-1;
for(int to:e[v2]){
if(((s>>(to-1))&1)==0){
cnt++;id=to;
}
}
if(cnt>1){
// printf("cnt>1 k=%d v1=%d v2=%d s=%d\n",k,v1,v2,s);
return (ans=0);
}
if(cnt==1){
ans=(ans+dfs(k+1,id,v1,s|(1ll<<(id-1))))%mod;
}
else{
rep(i,0,n-1){
if((s>>i)&1) continue;
int nw=i+1;
ans=(ans+dfs(k+1,nw,v1,s|(1ll<<i)))%mod;
}
}
}
// printf("End: k=%d v1=%d v2=%d s=%d ans=%d\n",k,v1,v2,s,ans);
return ans;
}
signed main(){
// freopen("my.in","r",stdin);
// freopen("my.out","w",stdout);
read(n);
rep(i,1,n-1){
int u,v;read(u);read(v);e[u].pb(v);e[v].pb(u);
}
int Ans=dfs(0,0,0,0);
printf("%lld\n",Ans);
return 0;
}
ZR2370
二分答案,考虑构造出来一个序列是困难的,所以我们不妨想把从原序列删数制止合法。首先显然是把数字从大往小删,如果一个数与它左右相邻的数不合法,那么就删掉,用一个链表来维护删除即可。
#include<bits/stdc++.h>
#define mset(a,b) memset((a),(b),sizeof((a)))
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
#define dec(i,l,r) for(int i=(r);i>=(l);i--)
#define cmax(a,b) (((a)<(b))?(a=b):(a))
#define cmin(a,b) (((a)>(b))?(a=b):(a))
#define Next(k) for(int x=head[k];x;x=li[x].next)
#define vc vector
#define ar array
#define pi pair
#define fi first
#define se second
#define mp make_pair
#define pb emplace_back
#define N 500010
#define M number
using namespace std;
typedef double dd;
typedef long double ld;
typedef unsigned int uint;
typedef unsigned long long ull;
#define ll long long
typedef pair<int,int> P;
typedef vector<int> vi;
const int INF=0x3f3f3f3f;
const dd eps=1e-9;
template<typename T> inline void read(T &x) {
x=0; int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
x*=f;
}
int n,K,a[N],L[N],R[N],b[N];
inline void del(int k){
R[L[k]]=R[k];
L[R[k]]=L[k];
}
inline bool chk(int mid){
rep(i,1,n) L[i]=i-1,R[i]=i+1;
R[n]=1;L[1]=n;
int tot=n;
rep(i,1,n){
int l=L[b[i]],r=R[b[i]];
if(a[l]+a[b[i]]>mid||a[r]+a[b[i]]>mid) del(b[i]),tot--;
}
return tot>=K;
}
signed main(){
// freopen("my.in","r",stdin);
// freopen("my.out","w",stdout);
read(n);read(K);rep(i,1,n) read(a[i]);
rep(i,1,n) b[i]=i;
sort(b+1,b+n+1,[&](int i,int j){return a[i]>a[j];});
ll l=1,r=2e9;
while(l<r){
// printf("l=%d r=%d\n",l,r);
int mid=(l+r)>>1;
if(chk(mid)) r=mid;
else l=mid+1;
}
printf("%lld\n",l);
return 0;
}
ZR2446
首先我们可以固定一个左端点,接下来就是选择一个右端点。
容易发现,右端点的选取与一些后缀之间的排序有关,但是这些后缀后面还有可能会接一些东西, 场上一直在想 SA,这就导致了这个题没有思路。
但实际上,后面的那些接上去的东西,一样是字符串的一些后缀,而他们的哈希值都是可以提前预处理出来的,这提示我们可以在
ZR2448
首先可以建出括号序,而我们的路径很像是先往祖先走,然后按着兄弟走,然后再往下走,大致这样的一个过程。
于是我们可以预处理出每个点走
注意程序中的预处理。这样预处理的正确性可以归纳证明,若
这个证明非常不严谨,但是感受一下应该是对的,目前博主才疏学浅并不能够证明,但是感性理解尽可能往左走和尽可能往右走总有一个是正确的。
由此,我们接下来对于每个询问相当于让
#include<bits/stdc++.h>
#define mset(a,b) memset((a),(b),sizeof((a)))
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
#define dec(i,l,r) for(int i=(r);i>=(l);i--)
#define cmax(a,b) (((a)<(b))?(a=b):(a))
#define cmin(a,b) (((a)>(b))?(a=b):(a))
#define Next(k) for(int x=head[k];x;x=li[x].next)
#define vc vector
#define ar array
#define pi pair
#define fi first
#define se second
#define mp make_pair
#define pb emplace_back
#define N 400010
#define M number
using namespace std;
typedef double dd;
typedef long double ld;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
//#define int long long
typedef pair<int,int> P;
typedef vector<int> vi;
const int INF=0x3f3f3f3f;
const dd eps=1e-9;
template<typename T> inline void read(T &x) {
x=0; int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
x*=f;
}
char s[N];
int sta[N],top,n,a[N],L[N][21],R[N][21],m;
int main(){
// freopen("my.in","r",stdin);
// freopen("my.out","w",stdout);
scanf("%s",s+1);
n=strlen(s+1);
rep(i,1,n){
if(s[i]=='(') sta[++top]=i;
else{
a[i]=sta[top];
a[sta[top]]=i;
top--;
}
}
rep(i,1,n){
L[i][0]=max(min(i-1,a[i]),0);
R[i][0]=min(max(i+1,a[i]),n);
}
rep(j,1,20){
rep(i,1,n){
L[i][j]=min(L[L[i][j-1]][j-1],L[R[i][j-1]][j-1]);
R[i][j]=max(R[R[i][j-1]][j-1],R[L[i][j-1]][j-1]);
}
}
read(m);
rep(i,1,m){
int x,y;read(x);read(y);
if(x==y){
puts("0");continue;
}
if(x>y) swap(x,y);
int l,r;
l=r=x;
int ans=0;
dec(i,0,20){
int nl=min(L[l][i],L[r][i]);
int nr=max(R[l][i],R[r][i]);
if(nr<y){
l=nl;r=nr;ans+=(1<<i);
}
}
x=r;l=r=y;
// printf("ans=%d x=%d\n",ans,x);
dec(i,0,20){
int nl=min(L[l][i],L[r][i]);
int nr=max(R[l][i],R[r][i]);
// printf("i=%d nl=%d nr=%d\n",i,nl,nr);
if(nl>x){
l=nl;r=nr;ans+=(1<<i);
}
}
// printf("ans=%d l=%d\n",ans,l);
ans++;
printf("%d\n",ans);
}
return 0;
}
ZR2457
原题:LOJ 花火
考虑能够作为左端点的值一定是前缀
这样一共还是要做
#include<bits/stdc++.h>
#define mset(a,b) memset((a),(b),sizeof((a)))
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
#define dec(i,l,r) for(int i=(r);i>=(l);i--)
#define cmax(a,b) (((a)<(b))?(a=b):(a))
#define cmin(a,b) (((a)>(b))?(a=b):(a))
#define Next(k) for(int x=head[k];x;x=li[x].next)
#define vc vector
#define ar array
#define pi pair
#define fi first
#define se second
#define mp make_pair
#define pb emplace_back
#define N 1000100
#define M number
using namespace std;
typedef double dd;
typedef long double ld;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
//#define int long long
typedef pair<int,int> P;
typedef vector<int> vi;
const int INF=0x3f3f3f3f;
const dd eps=1e-9;
template<typename T> inline void read(T &x) {
x=0; int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
x*=f;
}
int n,a[N],b[N],c[N];
struct Ques{
int l,r,v;
inline Ques(){}
inline Ques(int l,int r,int v) : l(l),r(r),v(v) {}
};
vc<Ques> q[N];
struct Node{
int maxx,tag;
}p[N<<2];
struct SegmentTree{
#define ls(k) k<<1
#define rs(k) k<<1|1
inline void pushup(int k){
p[k].maxx=max(p[ls(k)].maxx,p[rs(k)].maxx);
}
inline void A(int k,int x){
p[k].maxx+=x;
p[k].tag+=x;
}
inline void pushdown(int k){
if(p[k].tag){
A(ls(k),p[k].tag);A(rs(k),p[k].tag);p[k].tag=0;
}
}
inline void change(int k,int l,int r,int z,int y,int x){
if(z<=l&&r<=y){
A(k,x);return;
}int mid=(l+r)>>1;pushdown(k);
if(z<=mid) change(ls(k),l,mid,z,y,x);
if(mid<y) change(rs(k),mid+1,r,z,y,x);
pushup(k);
}
}st;
inline int binale(int l,int r,int v,int *f){
if(l>r) return -1;
while(l<r){
int mid=(l+r+1)>>1;
if(a[f[mid]]<=v) l=mid;
else r=mid-1;
}
if(a[f[l]]<=v) return l;
return -1;
}
inline int binage(int l,int r,int v,int *f){
if(l>r) return -1;
while(l<r){
int mid=(l+r)>>1;
if(a[f[mid]]>=v) r=mid;
else l=mid+1;
}
if(a[f[l]]>=v) return l;
return -1;
}
int main(){
// freopen("my.in","r",stdin);
// freopen("my.out","w",stdout);
read(n);rep(i,1,n) read(a[i]);
b[1]=1;
rep(i,2,n){
if(a[i]>a[b[i-1]]) b[i]=i;
else b[i]=b[i-1];
}
c[n]=n;
dec(i,1,n-1){
if(a[i]<a[c[i+1]]) c[i]=i;
else c[i]=c[i+1];
}
rep(i,1,n){
int l=binage(1,i-1,a[i],b);
int r=binale(i+1,n,a[i],c);
// printf("i=%d l=%d r=%d\n",i,l,r);
if(l==-1||r==-1) continue;
q[l].pb(i+1,r,2);q[i].pb(i+1,r,-2);
// printf("id=%d l=%d r=%d v=%d\n",l,i+1,r,2);
// printf("id=%d l=%d r=%d v=%d\n",i,i+1,r,-2);
}
// rep(i,1,n){
// int l=binale(1,i-1,a[i],b);
// int r=binale(i+1,n,a[i],c);
// if(l==-1||r==-1) continue;
// printf("i=%d\n",i);
// q[1].pb(i+1,r,-1);q[l+1].pb(i+1,r,1);
// printf("id=%d l=%d r=%d v=%d\n",1,i+1,r,-1);
// printf("id=%d l=%d r=%d v=%d\n",l+1,i+1,r,1);
// }
// rep(i,1,n){
// int l=binage(1,i-1,a[i],b);
// int r=binage(i+1,n,a[i],c);
// if(l==-1||r==-1) continue;
// printf("i=%d\n",i);
// q[l].pb(r,n,-1);q[i].pb(r,n,1);
// printf("id=%d l=%d r=%d v=%d\n",l,r,n,-1);
// printf("id=%d l=%d r=%d v=%d\n",i,r,n,1);
// }
int ans=0;
rep(i,1,n){
for(Ques now:q[i]){
st.change(1,1,n,now.l,now.r,now.v);
}
ans=max(ans,p[1].maxx);
}
printf("%d\n",ans+1);
return 0;
}
ZR2459
若给定排列,如果加油量减耗油量小于
设这个折线上的点为
考虑如何计算
#include<bits/stdc++.h>
#define mset(a,b) memset((a),(b),sizeof((a)))
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
#define dec(i,l,r) for(int i=(r);i>=(l);i--)
#define cmax(a,b) (((a)<(b))?(a=b):(a))
#define cmin(a,b) (((a)>(b))?(a=b):(a))
#define Next(k) for(int x=head[k];x;x=li[x].next)
#define vc vector
#define ar array
#define pi pair
#define fi first
#define se second
#define mp make_pair
#define pb emplace_back
#define N 21
#define M 2000100
using namespace std;
typedef double dd;
typedef long double ld;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
#define int long long
typedef pair<int,int> P;
typedef vector<int> vi;
const int INF=0x3f3f3f3f;
const dd eps=1e-9;
const int mod=1e9+7;
template<typename T> inline void read(T &x) {
x=0; int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
x*=f;
}
int n,a[N],b[N],c[N],f[M],g[M],sum[M];
signed main(){
// freopen("my.in","r",stdin);
// freopen("my.out","w",stdout);
read(n);rep(i,1,n) read(a[i]),read(b[i]),c[i]=a[i]-b[i];
rep(i,1,n) sum[(1<<(i-1))]=c[i];
rep(i,0,(1<<n)-1){
sum[i]=sum[i&(-i)]+sum[i^(i&(-i))];
}
if(sum[(1<<n)-1]<0){puts("0");return 0;}
g[0]=f[0]=1;
rep(i,0,(1<<n)-1){
if(sum[i]>=0){
rep(j,0,n-1) if((i>>j)&1) (g[i]+=g[i^(1<<j)])%=mod;
}
else{
rep(j,0,n-1) if((i>>j)&1) (f[i]+=f[i^(1<<j)])%=mod;
}
}
int ans=0;
rep(i,0,(1<<n)-1){
ans=(ans+f[i]*g[((1<<n)-1)^i]%mod*(__builtin_popcountll(i)+1)%mod)%mod;
}
printf("%lld\n",ans);
return 0;
}
ZR2458
这里只说明
其中,
瓶颈在求阶乘上,不过我们可以利用分块打表,在可以接受的时间复杂度内预处理所有可能需要的阶乘。
ZR2461
场上想用线段树合并来维护每个节点的值,其实不用,依然是从大往小加边的思路,不过我们只需要维护连通块内答案最小的点就行了,所以我们可以简单分析一些性质让我们维护尽可能少的值。
ZR2463
设质数
ZR2462
其实这种题目和哈夫曼树半点关系没有,但是我被吓傻了。
首先显然有一个树的结构,而根节点的每个儿子把所有的点划分成了若干区间,这就提示我们区间 DP。
设
容易发现如果一个点所有的子节点不都是儿子,那么这个点一定有
实现细节较多。
#include<bits/stdc++.h>
#define mset(a,b) memset((a),(b),sizeof((a)))
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
#define dec(i,l,r) for(int i=(r);i>=(l);i--)
#define cmax(a,b) (((a)<(b))?(a=b):(a))
#define cmin(a,b) (((a)>(b))?(a=b):(a))
#define Next(k) for(int x=head[k];x;x=li[x].next)
#define vc vector
#define ar array
#define pi pair
#define fi first
#define se second
#define mp make_pair
#define pb emplace_back
#define N 510
#define M number
using namespace std;
typedef double dd;
typedef long double ld;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
#define int long long
typedef pair<int,int> P;
typedef vector<int> vi;
const int INF=1e18;
const dd eps=1e-9;
template<typename T> inline void read(T &x) {
x=0; int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
x*=f;
}
int n,K,a[N],f[N][N][6],ans[N][N],lg2[N],g[N][N][6],dk[6],sp;
signed main(){
// freopen("my.in","r",stdin);
// freopen("my.out","w",stdout);
read(n);read(K);rep(i,1,n) read(a[i]);
rep(i,0,5) dk[i]=-1;
rep(i,0,5) dec(j,0,i) if((K>>j)&1){
dk[i]=j;break;
}
// rep(i,0,5){
// printf("dk[%d]=%d\n",i,dk[i]);
// }
lg2[0]=-1;rep(i,1,K) lg2[i]=lg2[i>>1]+1;
sp=lg2[K&(-K)];
// printf("sp=%d\n",sp);
rep(i,1,n){
f[i][i][0]=0;ans[i][i]=0;
rep(j,1,5) f[i][i][j]=INF;
}
rep(i,2,n){
rep(j,1,n-i+1){
int l=j,r=j+i-1;
int len=r-l+1;
rep(k,0,5) f[l][r][k]=INF,g[l][r][k]=INF;
rep(o,1,5)if(len>=(1<<o)){
rep(k,l,r) f[l][r][o]=min(f[l][r][o],f[l][k][o-1]+f[k+1][r][o-1]);
}
rep(o,0,5){
if(dk[o]==-1){
g[l][r][o]=INF;
continue;
}
if(dk[o]==sp){
g[l][r][o]=f[l][r][dk[o]];
}
else{
rep(k,l,r){
g[l][r][o]=min(g[l][r][o],g[l][k][dk[o]-1]+f[k+1][r][dk[o]]);
}
}
}
// printf("g[1][4][1]=%d\n",g[1][4][1]);
if(len<=K){
rep(k,l,r) ans[l][r]+=a[k];
f[l][r][0]=ans[l][r];
rep(o,0,5) if(dk[o]==0) g[l][r][o]=ans[l][r];
}
else{
ans[l][r]=g[l][r][5];
rep(k,l,r) ans[l][r]+=a[k];
f[l][r][0]=ans[l][r];
rep(o,0,5) if(dk[o]==0) g[l][r][o]=ans[l][r];
}
// rep(o,0,5){
// printf("f[%lld][%lld][%lld]=%lld\n",l,r,o,f[l][r][o]);
// printf("g[%lld][%lld][%lld]=%lld\n",l,r,o,g[l][r][o]);
// }
}
}
printf("%lld\n",ans[1][n]);
return 0;
}
ZR2464
考虑这样奇怪的数据范围一定是折半搜索,我们考虑先分成两半。又有一个转化:
考虑贡献分为三部分,左边集合,右边集合,左右集合之间的边。
固定一个左边集合,对于右边集合中的每一个点,如果这个点到左边集合的边数量为偶数,那么等价于这些边都不存在,所以我们只需要关注那些到左边集合边数为奇数的右边集合的点,设
考虑如果直接枚举左右两边集合,复杂度不会减少,不如对于右边集合预处理一个
容易发现对于每个
#include<bits/stdc++.h>
#define mset(a,b) memset((a),(b),sizeof((a)))
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
#define dec(i,l,r) for(int i=(r);i>=(l);i--)
#define cmax(a,b) (((a)<(b))?(a=b):(a))
#define cmin(a,b) (((a)>(b))?(a=b):(a))
#define Next(k) for(int x=head[k];x;x=li[x].next)
#define vc vector
#define ar array
#define pi pair
#define fi first
#define se second
#define mp make_pair
#define pb emplace_back
#define N 50
#define M 23
using namespace std;
typedef double dd;
typedef long double ld;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
#define int long long
typedef pair<int,int> P;
typedef vector<int> vi;
const int INF=0x3f3f3f3f;
const dd eps=1e-9;
const int mod=998244353;
template<typename T> inline void read(T &x) {
x=0; int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
x*=f;
}
int B,e[N],n,m,f[1ll<<M],g[1ll<<M],bit[1ll<<M],h[1ll<<M];
unordered_map<ll,int> lg2;
inline void FWTxor(int *f,int n){
for(int mid=1;mid<=(n>>1);mid<<=1)
for(int l=0;l<n;l+=(mid<<1))
for(int i=l;i<=l+mid-1;i++){
int a=f[i],b=f[i+mid];
f[i]=(a+b)%mod;f[i+mid]=(a-b)%mod;
}
}
inline int ksm(int a,int b,int mod){
int res=1;while(b){if(b&1)res=1ll*res*a%mod;a=1ll*a*a%mod;b>>=1;}return res;
}
inline int inv(int x){return ksm(x,mod-2,mod);}
signed main(){
// freopen("my.in","r",stdin);
// freopen("my.out","w",stdout);
read(n);read(m);
rep(i,1,m){
int u,v;read(u);read(v);
e[u]|=(1ll<<(v-1));
e[v]|=(1ll<<(u-1));
}
// rep(i,1,n){
// printf("i=%d e[i]=%d\n",i,e[i]);
// }
// lg2[0]=-1;
B=n/2;
rep(i,0,(1ll<<(max(B,n-B)))-1) bit[i]=bit[i>>1]^(i&1);
rep(i,0,n) lg2[1ll<<i]=i;
// rep(i,1,(1ll<<(max(B,n-B)))-1) lg2[i]=lg2[i>>1]+1;
rep(i,0,(1ll<<B)-1){
h[i]=h[i^(i&(-i))]^bit[e[lg2[i&(-i)]+1]&i];
// assert((e[lg2[i&(-i)]+1]&i)<=(1ll<<(max(B,n-B)))-1);
// printf("h[%d]=%lld\n",i,h[i]);
int now=0;
rep(j,B+1,n){
if(bit[e[j]&i]){
// assert((e[j]&i)<=(1ll<<(max(B,n-B)))-1);
now|=(1ll<<(j-B-1));
}
}
// printf("i=%d now=%d\n",i,now);
if(h[i]) f[now]--;
else f[now]++;
}
// printf("lg2[1]=%d\n",lg2[1]);
rep(i,0,(1ll<<(n-B))-1){
h[i]=0;
if(!i){
g[0]=1;
continue;
}
h[i]=h[i^(i&(-i))]^bit[(e[lg2[i&(-i)]+B+1]&(i<<(B)))>>B];
// assert(((e[lg2[i&(-i)]+B+1]&(i<<(B)))>>B)<=(1ll<<(max(B,n-B)))-1);
// printf("i=%lld i&(-i)=%lld,val=%lld,e[lg2[i&(-i)]+B+1]=%d\n",i,i&(-i),lg2[i&(-i)]+B+1,e[lg2[i&(-i)]+B+1]);
if(h[i]) g[i]--;
else g[i]++;
}
// exit(0);
rep(i,0,(1ll<<(n-B))-1){
// printf("f[%lld]=%lld\n",i,f[i]);
// printf("g[%lld]=%lld\n",i,g[i]);
f[i]%=mod;
g[i]%=mod;
}
FWTxor(g,1ll<<(n-B));
rep(i,0,(1ll<<(n-B))-1) f[i]=f[i]*g[i]%mod;
int ans=0;
rep(i,0,(1ll<<(n-B))-1) ans=(ans+f[i])%mod;
// printf("ans=%lld\n",ans);
(ans+=((1ll<<(n))%mod))%=mod;
ans=ans*inv(2)%mod;
printf("%lld\n",ans);
return 0;
}
ZR2447
考虑若小于等于
因为自己实现的太丑以至于调不出来,这里来一份别人的简单易懂代码。
#include<cstdio>
using namespace std;
const int o=210,MOD=1e9+7;
int T,n,m,K,h[o],cnt,mp[o][o],dif[o],sam[o],coef[o],col[o],d[o],f[o][o],g[o],b[o],tot,asd,ans;bool tr[o],sp[o];
struct Edge{int v,p,id;}e[o];
inline void ad(int U,int V,int ID){e[++cnt].v=V;e[cnt].p=h[U];e[h[U]=cnt].id=ID;}
void Dfs(int nw,int fa){
d[nw]=d[fa]+1;
for(int i=h[nw];i;i=e[i].p) if(e[i].v^fa)
if(d[e[i].v]>d[nw]) sp[nw]=1;
else if(!d[e[i].v]) tr[i]=1,d[e[i].v]=d[nw]+1,Dfs(e[i].v,nw);
if(sp[nw]) b[++tot]=nw;
}
void dfs(int nw,int fa){
for(int i=0;i<=asd;++i) f[nw][i]=(col[nw]==i||!sp[nw]);
for(int i=h[nw];i;i=e[i].p) if(e[i].v^fa)
if(!tr[i]){if(d[nw]>d[e[i].v]) for(int j=0;j<=asd;++j) f[nw][j]=f[nw][j]*1ll*(col[e[i].v]==j?sam[e[i].id]:dif[e[i].id])%MOD;}
else{
dfs(e[i].v,nw);
for(int j=0;j<=asd;++j) f[nw][j]=((g[e[i].v]+MOD-f[e[i].v][j])*1ll*dif[e[i].id]+f[e[i].v][j]*1ll*sam[e[i].id])%MOD*f[nw][j]%MOD;
}
g[nw]=f[nw][0]*1ll*(K-asd)%MOD;
for(int i=1;i<=asd;++i) g[nw]=(g[nw]+f[nw][i])%MOD;
}
void ddfs(int nw){
if(nw>tot){dfs(1,0);ans=(ans+coef[asd]*1ll*g[1])%MOD;return;}
for(int i=1;i<=asd;++i) col[b[nw]]=i,ddfs(nw+1);
col[b[nw]]=++asd;ddfs(nw+1);--asd;
}
int main(){
for(scanf("%d",&T);T--;printf("%d\n",ans),ans=cnt=tot=0){
scanf("%d%d%d",&n,&m,&K);
for(int i=1;i<=n;++i) h[i]=d[i]=col[i]=0;
for(int i=1;i<=2*m;++i) tr[i]=sp[i]=0;
for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) mp[i][j]=0;
for(int i=1,u,v,a,b;i<=m;++i){
scanf("%d%d%d%d",&u,&v,&a,&b);
if(!mp[u][v]) dif[i]=a,sam[i]=b,mp[u][v]=mp[v][u]=i,ad(u,v,i),ad(v,u,i);
else dif[mp[u][v]]=dif[mp[u][v]]*1ll*a%MOD,sam[mp[u][v]]=sam[mp[u][v]]*1ll*b%MOD;
}
for(int i=coef[0]=1;i<=n;++i) coef[i]=coef[i-1]*(K-i+1ll)%MOD;
Dfs(1,0);ddfs(1);
}
return 0;
}
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现