开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 9 天,点击查看活动详情
D1 - Xor-Subsequence (easy version) dp
没能及时得看出规律来,淦,,
看到a只有200,可以发现异或这个操作只对二进制得后七位产生作用,所以我就像如果j<255,i>255的话i和j就不用比较了,一定是i大;但是却没想到其实对所有的i,j都是满足这个条件的,i只有和大于等于i-256的j比较才管用,因为别的再怎么异或都无济于事,所以第二层循环只要枚举i-300到i-1就可以了
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll N = 1e6+100;
const ll mod=1e9+7;
ll t,n,dp[400005],a[400005];
int main(){
scanf("%lld",&t);
while(t--){
scanf("%lld",&n);
for(int i=0;i<n;i++) scanf("%lld",&a[i]);
for(int i=0;i<=n+10;i++) dp[i]=1;
ll maxx=1;
for(ll i=0;i<n;i++)
for(ll j=max(0LL,i-300);j<i;j++){
if((a[j]^i)<(a[i]^j)) dp[i]=max(dp[i],dp[j]+1);
maxx=max(maxx,dp[i]);
}
printf("%lld\n",maxx);
}
return 0;
}
441C - Valera and Tubes
模拟矩阵螺旋构造,难的不在于思路而在于代码,思路无非就是每次都构造n*m/k个,最后一个把剩下的格子都按顺序输出就行
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll N = 1e6+100;
const ll mod=1e9+7;
ll n,m,k,a[305][305];
int main(){
scanf("%lld%lld%lld",&n,&m,&k);
ll x=1,y=1,z=n*m/k,cnt=n*m,xn=1,ym=1,flag=0,zz;
for(int i=1;i<=k;i++){
if(i!=k) printf("%lld ",z),zz=z;
else printf("%lld ",cnt),zz=cnt;
while(zz--){
printf("%lld %lld ",x,y);
if(flag==0){
y++;
if(y>m){
y--;x++;flag=1;
xn++;
}
}
else if(flag==1){
x++;
if(x>n){
x--;y--;flag=2;
m--;
}
}
else if(flag==2){
y--;
if(y<ym){
y++;x--;flag=3;
n--;
}
}
else if(flag==3){
x--;
if(x<xn){
x++;y++;flag=0;
ym++;
}
}
cnt--;
}
printf("\n");
}
return 0;
}
1234D - Distinct Characters Queries 树状数组
可以发现字符串中只有字母,那么我们就直接开26个树状数组然后进行操作就可以,1操作我们就将原来字母的树状数组的这个位置-1,替换字母的树状数组的这个位置+1,同时把字符串数组更新;2操作直接遍历每个字符数组都查询一遍,如果不为0说明这个区间有这个字母,ans++
#include <bits/stdc++.h>
#define ll long long
#define lowbit(i) (i)&(-i)
using namespace std;
const ll N = 1e6+100;
const ll mod=1e9+7;
ll q,n,t[30][100005];
char s[100005];
void add(ll x,ll y,ll j){
for(int i=x;i<=n;i+=lowbit(i))
t[j][i]+=y;
}
ll ask(ll x,ll j){
ll res=0;
for(int i=x;i;i-=lowbit(i))
res+=t[j][i];
return res;
}
int main(){
scanf("%s",s+1);
n=strlen(s+1);
for(int i=1;i<=n;i++){
add(i,1,s[i]-'a'+1);
}
scanf("%lld",&q);
while(q--){
ll op,x,y;
char re[2];
scanf("%lld%lld",&op,&x);
if(op==1){
scanf("%s",re);
add(x,-1,s[x]-'a'+1);
add(x,1,re[0]-'a'+1);
s[x]=re[0];
}
else{
scanf("%lld",&y);
ll ans=0;
for(int i=1;i<=26;i++){
if(ask(y,i)-ask(x-1,i)>0) ans++;
}
printf("%lld\n",ans);
}
}
return 0;
}
P2831 [NOIP2016 提高组] 愤怒的小鸟 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 状压dp
昨天没来得及写代码的那个题,之所以可以按第一个没打的猪的坐标来遍历n个猪是因为这样是可以做到不漏的,这样遍历也是可以做到把每条抛物线都遍历到,因为一共2^n个状态,每个猪都可能是第一个没被打中的,所以这样就可以让复杂度少一个n,就可以顺利过掉该题了
题解 P2831 【愤怒的小鸟】 - Deep_Dark_Boy 的博客 - 洛谷博客
#include <bits/stdc++.h>
#define ll long long
#define lowbit(i) (i)&(-i)
using namespace std;
const ll N = 1e6+100;
const ll mod=1e9+7;
const double eps=1e-8;
ll t,n,m,dp[1100000],start[1100000],line[20][20];
double x[20],y[20];
void cal(double &a,double &b,ll i,ll j){
a=-(y[i]*x[j]-y[j]*x[i])/(x[j]*x[j]*x[i]-x[i]*x[i]*x[j]);
b=(y[i]*x[j]*x[j]-y[j]*x[i]*x[i])/(x[i]*x[j]*x[j]-x[j]*x[i]*x[i]);
}
int main(){
scanf("%lld",&t);
for(int i=0;i<(1<<18);i++){
int j=1;
while(j<=18&&i&(1<<(j-1))) j++;
start[i]=j;
}
while(t--){
scanf("%lld%lld",&n,&m);
for(int i=0;i<(1<<n);i++) dp[i]=1e18;
memset(line,0,sizeof(line));
dp[0]=0;
for(int i=1;i<=n;i++) scanf("%lf%lf",&x[i],&y[i]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
if(fabs(x[i]-x[j])<eps) continue;
double a,b;
cal(a,b,i,j);
if(a>-eps) continue;
for(int k=1;k<=n;k++)
if(fabs(a*x[k]*x[k]+b*x[k]-y[k])<=eps) line[i][j]|=(1<<k-1);
}
for(int s=0;s<(1<<n);s++){
ll j=start[s];
dp[s|(1<<(j-1))]=min(dp[s|(1<<(j-1))],dp[s]+1);
for(int i=1;i<=n;i++){
dp[s|line[j][i]]=min(dp[s|line[j][i]],dp[s]+1);
}
}
printf("%lld\n",dp[(1<<n)-1]);
}
return 0;
}
P2915 [USACO08NOV]Mixed Up Cows G - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 状压dp
统计方案数是要dp[s|(1<<j-1)][j]+=dp[s][i];而不是+1,,,
其他的就是一个经典的排队问题,只需要判断一下差的绝对值是否是小于k的就行了
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll N = 1e6+100;
const ll mod=1e9+7;
ll n,k,dp[100005][20],a[20];
int main(){
scanf("%lld%lld",&n,&k);
for(ll i=1;i<=n;i++) scanf("%lld",&a[i]),dp[1<<(i-1)][i]=1;
for(ll s=0;s<(1<<n);s++)
for(ll i=1;i<=n;i++){
//if(!(s&(1<<(i-1)))) continue;
for(ll j=1;j<=n;j++){
if(i==j) continue;
if(abs(a[j]-a[i])<=k||s&(1<<j-1)) continue;
dp[s|(1<<j-1)][j]+=dp[s][i];
}
}
ll ans=0;
for(ll i=1;i<=n;i++) ans+=dp[(1<<n)-1][i];
printf("%lld\n",ans);
return 0;
}
F-至至子的公司排队_牛客小白月赛55 (nowcoder.com) 树形dp 可重集排列
这个题最大的收获还是知道可重集排列是怎么算了吧,假设有集合{1,2,2,3,3,3,4,4,4,4},则他们的排列为编辑,之后这个题就是按这个公式去求就行了,最后求n家公司的排列也是一个可重集排列,另外在求每一家公司的时候dp[u]=
可重集排列
#include <bits/stdc++.h>
#define ll long long
#define lowbit(i) (i)&(-i)
using namespace std;
const ll N = 1e6+100;
const ll M=1e5;
const ll mod=1e9+7;
const ll inf=1e18;
const double eps=1e-8;
ll qpow(ll a,ll b){
ll res=1;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
ll getinv(ll a){return qpow(a,mod-2);}
ll n,cnt,head[200005],fac[200005],ifac[200005],dp[100005],siz[100005];
struct Edge{
ll from,to,next;
}edge[200005];
void addedge(ll from,ll to){
edge[++cnt].from=from;
edge[cnt].to=to;
edge[cnt].next=head[from];
head[from]=cnt;
}
vector<ll>g[100005];
void init(){
fac[0]=1;
for(ll i=1;i<=100000;i++) fac[i]=fac[i-1]*i%mod;
ifac[100000]=getinv(fac[100000]);
for(ll i=99999;i>=0;i--)
ifac[i]=(i+1LL)*ifac[i+1]%mod;
}
void dfs(ll u){
siz[u]=dp[u]=1;
// for(int i=head[u];i;i=edge[i].next){
// ll j=edge[i].to;
// if(j==fa) continue;
// dfs(j,u);
// dp[u]=(dp[u]*dp[j]%mod)*ifac[siz[j]]%mod;
// siz[u]+=siz[j];
// }
for(auto &v:g[u]){
// cout<<v<<" "<<u<<endl;
dfs(v);
dp[u]=(dp[u]*dp[v]%mod)*ifac[siz[v]]%mod;
siz[u]+=siz[v];
}
dp[u]=dp[u]*fac[siz[u]-1]%mod;
}
void dfs(ll u,ll fa){
siz[u]=dp[u]=1;
for(int i=head[u];i;i=edge[i].next){
ll j=edge[i].to;
if(j==fa) continue;
dfs(j,u);
dp[u]=(dp[u]*dp[j]%mod)*ifac[siz[j]]%mod;
siz[u]+=siz[j];
}
dp[u]=dp[u]*fac[siz[u]-1]%mod;
}
int main(){
scanf("%lld",&n);
init();
ll c,a,ans=1,tot=0;
for(int i=1;i<=n;i++){
scanf("%lld",&c); tot+=c;
// for(int j=1;j<=c;j++) g[j].clear();
for(int j=2;j<=c;j++){
scanf("%lld",&a);
// g[a].push_back(j);
addedge(a,j);
addedge(j,a);
}
// cout<<"halo"<<endl;
dfs(1,0);
ans=(ifac[c]*ans%mod)*dp[1]%mod;
//ans = 1LL * ifac[c] * ans % mod * solve(c) % mod;
for(int j=0;j<=c;j++) head[j]=edge[j].from=edge[j].to=edge[j].next=0;
}
ans=ans*fac[tot]%mod;
printf("%lld\n",ans);
return 0;
}