A:
这是一道逗鹅题
队友一上来猜结论 猜对了
但是wa了
然后就扔了这题了
最后我暴力发现队友的结论没错
然后鹅发现没累乘
D:
找团好像没什么快的方法
只能是暴力
这个题虽然团有很多很多个
但是我们只找前k小的就行
现在的问题在于我们不能按照从小到大依次访问到每个团
第一个方法是用优先队列
我们一开始把单个的点扔进去
每次弹出来一个权值最小的团
我们虽然不能保证队列里的前k个就是当前的前k小
但是我们能保证现在队首的是当前最小的
因为后面在队列里的状态一定比他大
还没访问的到状态是由队列里的转移过去的 会更大
所以每次弹出队首一定是正确的
然后对于队首的状态 他能到达的状态拿到队列里
这样子 只需要k次弹出就结束了
每次弹出然后拓展->O(logn+n*X)
X这里暴力的话是n,就是循环,会tle
然后用int128或者bitset优化一下就好了
第二个方法是二分
回到前面的问题
我们不能依次从小到大遍历所有的团
但是如果我们知道一个lim
我们现在要找权值<=lim的团们
这样我们就可以暴力的搜索
如果拓展到一个合法的团 那就继续
这样的操作会使得k--
如果扩展到一个不合法的 就停止
这样只会浪费一次 不会在非法的道路上走得很远
而这个lim又有单调性 就可以二分
O(log MAX_lim * k * X)
这个X是每次找到一个新的最大团时间
可以用int128优化
#include<cstdio> #include<cstring> #include<iostream> #include<queue> #define maxn 110 #define tpc __int128 #define ll long long using namespace std; ll n,k,w[maxn]; tpc G[maxn]; struct node{ ll big,val; tpc S; bool operator < (const node &A )const{ return A.val<val; } }; priority_queue<node>q; char s[maxn][maxn]; int main(){ scanf("%lld%lld",&n,&k); k--;node now,tmp; for(ll i=1;i<=n;i++) scanf("%lld",&w[i]); for(ll i=1;i<=n;i++) scanf("%s",s[i]+1); for(ll i=1;i<=n;i++){ for(ll j=1;j<=n;j++) if(s[i][j]=='1')G[i]+=tpc(1)<<j; now.val=w[i];now.S=tpc(1)<<i; now.big=i;q.push(now); } now.val=0; for(ll i=1;i<=k;i++){ if(q.empty()){ now.val=-1;break; } now=q.top();q.pop(); for(ll v=now.big+1;v<=n;v++){ if((G[v]&now.S)==now.S){ tmp.big=v;tmp.val=now.val+w[v]; tmp.S=now.S|(tpc(1)<<v);q.push(tmp); } } } printf("%lld\n",now.val); return 0; }
#include<cstdio> #include<cstring> #include<iostream> #include<queue> #include<bitset> #include<algorithm> #define tpc int #define maxn 110 #define ll long long using namespace std; int n,k,cnt; tpc G[maxn],S; ll ans,l,r; struct node{ int w,o; }a[maxn]; char s[maxn][maxn]; int cmp(const node &A,const node &B){ return A.w<B.w; } void Dfs(int now,ll val,ll lim){ int id=a[now].o; if(now==n+1||cnt>=k)return; if(val+a[now].w>lim)return; if((G[id]&S)==S){ cnt++;S|=tpc(1)<<id; Dfs(now+1,val+a[now].w,lim); S^=tpc(1)<<id; } Dfs(now+1,val,lim); } int main(){ scanf("%d%d",&n,&k); for(int i=1;i<=n;i++){ scanf("%d",&a[i].w);a[i].o=i;r+=a[i].w; } sort(a+1,a+1+n,cmp); for(int i=1;i<=n;i++) scanf("%s",s[i]+1); for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++) if(s[i][j]=='1')G[i]+=tpc(1)<<j; } if(k<=1){ printf("0\n");return 0; } k--;ans=-1; while(l<=r){ ll mid=(l+r)/2; cnt=0;S=0;Dfs(1,0,mid); if(cnt>=k){ ans=mid;r=mid-1; } else l=mid+1; } printf("%lld\n",ans); return 0; } /* 3 6 3 2 1 011 101 110 5 22 1 2 3 4 5 01111 10111 11011 11101 11110 5 22 5 4 3 2 1 01111 10111 11011 11101 11110 */
F:
暴力+最优化剪枝
ans=所有对之前的val和-队伍内部之间互相打架的val
后面这个val是递增的,就可以用最优化剪枝
#include<cstdio> #include<cstring> #include<iostream> #include<cstdlib> #define maxn 30 #define ll long long using namespace std; int n,g[maxn][maxn],A[maxn],B[maxn]; ll ans,sum; void Dfs(int now,ll s,int a,int b){ ll res; if(now==2*n+1){ if(ans<sum-s){ ans=sum-s;//printf("ans : %d\n",ans); //for(int i=1;i<=n*2;i++)printf("%d ",S[i]);printf("\n"); } return; } if(a<b){ res=0; for(int i=1;i<=a;i++) res+=g[now][A[i]]; if(sum-s-res>ans&&a<n){ A[a+1]=now;Dfs(now+1,s+res,a+1,b);A[a+1]=0; } res=0; for(int i=1;i<=b;i++) res+=g[now][B[i]]; if(sum-s-res>ans&&b<n){ B[b+1]=now;Dfs(now+1,s+res,a,b+1);B[b+1]=0; } } else { res=0; for(int i=1;i<=b;i++) res+=g[now][B[i]]; if(sum-s-res>ans&&b<n){ B[b+1]=now;Dfs(now+1,s+res,a,b+1);B[b+1]=0; } res=0; for(int i=1;i<=a;i++) res+=g[now][A[i]]; if(sum-s-res>ans&&a<n){ A[a+1]=now;Dfs(now+1,s+res,a+1,b);A[a+1]=0; } } } int main(){ scanf("%d",&n); for(int i=1;i<=n*2;i++) for(int j=1;j<=n*2;j++){ scanf("%d",&g[i][j]);sum+=g[i][j]; } sum/=2;Dfs(1,0,0,0);printf("%lld\n",ans); return 0; } /* 2 0 1 1000000000 1000000000 1 0 1000000000 1000000000 1000000000 1000000000 0 1 1000000000 1000000000 1 0 */
H:
枚举删除最大1矩阵的那个边
#include<iostream> #include<cstdio> #include<cstring> #define maxn 1010 using namespace std; int n,m,h[maxn][maxn],l[maxn][maxn],r[maxn][maxn],ans,x1,y1,x2,y2; char g[maxn][maxn],t[maxn]; int Solve(int falg){ memset(h,0,sizeof(h)); memset(l,0,sizeof(l)); memset(r,0,sizeof(r)); int res=0; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ l[i][j]=r[i][j]=j; if(g[i][j]=='0')continue; else h[i][j]=h[i-1][j]+1; } // printf("h:\n"); // for(int i=1;i<=n;i++){ // for(int j=1;j<=m;j++) // printf("%d ",h[i][j]); // printf("\n"); // } for(int i=1;i<=n;i++){ for(int j=2;j<=m;j++){ if(g[i][j]=='0')continue; while(h[i][l[i][j]-1]>=h[i][j]) l[i][j]=l[i][l[i][j]-1]; } } for(int i=1;i<=n;i++){ for(int j=m-1;j>=1;j--){ if(g[i][j]=='0')continue; while(h[i][r[i][j]+1]>=h[i][j]) r[i][j]=r[i][r[i][j]+1]; } } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ if(res<h[i][j]*(r[i][j]-l[i][j]+1)){ res=h[i][j]*(r[i][j]-l[i][j]+1); if(falg){ x1=i-h[i][j]+1;y1=l[i][j];x2=i;y2=r[i][j]; } } } return res; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%s",g[i]+1); Solve(1); for(int i=y1;i<=y2;i++){ t[i]=g[x1][i];g[x1][i]='0'; } ans=max(ans,Solve(0)); for(int i=y1;i<=y2;i++){ g[x1][i]=t[i]; } for(int i=y1;i<=y2;i++){ t[i]=g[x2][i];g[x2][i]='0'; } ans=max(ans,Solve(0)); for(int i=y1;i<=y2;i++){ g[x2][i]=t[i]; } for(int i=x1;i<=x2;i++){ t[i]=g[i][y1];g[i][y1]='0'; } ans=max(ans,Solve(0)); for(int i=x1;i<=x2;i++){ g[i][y1]=t[i]; } for(int i=x1;i<=x2;i++){ t[i]=g[i][y2];g[i][y2]='0'; } ans=max(ans,Solve(0)); for(int i=x1;i<=x2;i++){ g[i][y2]=t[i]; } printf("%d\n",ans); //printf("%d %d %d %d\n",x1,y1,x2,y2); return 0; } /* 5 6 001010 000110 010111 010111 000110 4 5 11011 01010 10110 00111 4 9 001110011 001110011 001110011 000000011 */