给日后的题解预留一个分割线
【ZOJ4098】【CODE】
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
#define N 1202020
using namespace std;
int n,m;
ll mo=1000000007;
ll f[N],dp[N],cons[N],cons1[N],cons2[N];
ll w[N],a[N],ban[N],ban2[N];
int bit[N];
ll quickmi(ll a,ll b){
ll t=1;
while(b>0){
if(b%2==1){
t=t*a%mo;
}a=a*a%mo;
b/=2;
}return t;
}
int lowbit(int x){return x&(-x);}
ll solve(){
if(n==1)return 0;
memset(f,0,sizeof(f));
memset(dp,0,sizeof(dp));
memset(ban,0,sizeof(ban));
memset(cons1,0,sizeof(cons1));
memset(cons2,0,sizeof(cons2));
ll ans=0;
int n1=n/2,n2=n-n1;
int sta1=1<<n1,sta2=1<<n2;
sta1--;sta2--;
f[0]=1;
for(int i=1;i<=sta2;i++){
int k=lowbit(i),id=bit[k];
f[i]=(f[i-k]+f[(i-k)-((i-k)&ban2[id+n/2])]*a[id+n/2]%mo)%mo;
}
ans=f[sta2];
dp[0]=1;
for(int i=1;i<=sta1;i++){
int k=lowbit(i),id=bit[k];
if(cons2[i-k]&(1ll<<(id-1)))continue;
cons2[i]=cons2[i-k]|cons[id];
ban[i]=ban[i-k]|ban2[id];
dp[i]=(dp[i]+dp[i-k]*a[id]%mo)%mo;
ans=(ans+dp[i]*f[sta2-ban[i]]%mo)%mo;
}
return ans;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=20;i++){
bit[1<<(i-1)]=i;
}
for(int i=1;i<=n;i++)scanf("%lld",&w[i]);
for(int i=1;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
cons[u]|=1ll<<(v-1);
cons[v]|=1ll<<(u-1);
if(v>n/2)ban2[u]|=1<<(v-n/2-1);
if(u>n/2)ban2[v]|=1<<(u-n/2-1);
}
for(int i=1;i<=n;i++)a[i]=1;
ll K=solve();
if(n==1)K=2;
for(int i=1;i<=n;i++)a[i]=w[i]*w[i]%mo;
ll A=solve();
if(n==1)A=(w[1]*w[1]+1)%mo;
for(int i=1;i<=n;i++)a[i]=w[i];
ll B=solve();
if(n==1)B=(w[1]+1);
B=B*B%mo;
A=A*K%mo;
K=K*K%mo;
printf("%lld\n",(A+mo-B)*quickmi(K,mo-2)%mo);
}
默默把数组改小以后时间复杂度还是没有进入top rank...
然后这个I题,大概就是在大多数情况下 决定某种上下的 某种界限...?
还没想好下一步打算做什么 : )