D1 T1 卡牌游戏
将2n个值(每张卡牌的AB面)混在一起从小到大排序并记录每一个值是A面还是B面
排序后答案显然是其中一段子序列的两端之差
这里以样例举例:
这样问题就转化为给2n个数要删除前面一段、后面一段,要求:
-
删除的A面总数不能超过要求
-
不能同时删除同一张卡的两面
对于第一条用一个变量动态实时记录即可
对于第二条用一个桶维护就可以完美解决了
空间复杂度:O(n)
时间复杂度:O(nlogn) 瓶颈在排序
代码:
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #define N 1000005 using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0' || ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0' && ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();} return x*f; } struct arr{ int x,id,op; }a[N<<1]; int n,k; inline bool cmp(arr A,arr B){return A.x<B.x;} bool vis[N]; int main() { n=read();k=read(); for(int i=1;i<=n;i++) a[i].x=read(),a[i].id=i,a[i].op=1; for(int i=1;i<=n;i++) a[i+n].x=read(),a[i+n].id=i; sort(a+1,a+(n<<1)+1,cmp); int l=0,r=(n<<1)+1,now=0,ans=2e9; while(!vis[a[r-1].id] && now+a[r-1].op<=k) vis[a[--r].id]=1,now+=a[r].op; while(!vis[a[l+1].id] && now+a[l+1].op<=k) vis[a[++l].id]=1,now+=a[l].op; while(r<(n<<1)) { ans=min(ans,a[r-1].x-a[l+1].x); vis[a[++r].id]=0; now-=a[r].op; while(!vis[a[l-1].id] && now+a[l-1].op<=k) vis[a[--l].id]=1,now+=a[l].op; } printf("%d ",ans); return 0; }
D1 T2 矩阵游戏
看到题面后注意到难点在于要控制构造出的原矩阵中每一个位置的数的值在0~1e6之间
那么先考虑没有这条限制的情况下如何构造出原矩阵
因为没有了限制不难发现我们只要钦定 ai,1=a1,j=0就可以生成一个唯一的矩阵a' (a'[i][j]=b[i][j]-a'[i+1][j]-a'[i][j+1]-a'[i+1][j+1])
我们再考虑通过调整某些位置的权值使得最后的解满足限制
手玩样例和推式子后我们可以发现:
1、对于某一行我们交替进行+r、-r、+r、-r……后的解仍然满足给定的矩阵b的限制
2、对于某一列我们交替进行+c、-c、+c、-c……后的解也仍然满足给定的矩阵b的限制
于是任意一组解都可以被我们表示为:
现在考虑0<=ai,j<=1e6这条限制,我们可以将r序列与c序列作为未知量进行差分约束
但是此时的差分约束的式子长成这样(设Ai,j为a‘i,j的“增量”,即ri与ci对a‘i,j的贡献):-ai,j<=Ai,j<=1e6-ai,j
由于Ai,j的形式不好看并不好进行差分约束(也不是不能,但好像超级麻烦)(差分约束的一般式子形式如:x<=y+val)
所以我们可以对奇数列的c序列取反,偶数行的r序列取反使得“奇列偶行”取反后的Ai,j的形式形如x-y
然后我们就可以得到一个很优美的矩阵:
然后就可以愉快的差分约束了(注意要开long long)
空间复杂度:O(n2)
最坏时间复杂度:O(n3) (本人加了双端队列优化所以时间复杂度在随机数据下会快亿一点,但可能也会被毒瘤数据卡歇逼)
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<vector> #include<queue> #include<deque> #define N 605 #define pb push_back #define mp make_pair using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0' || ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0' && ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();} return x*f; } int n,m,a[N][N],b[N][N]; vector<pair<int,int> > v[N]; deque<int> q; bool vis[N]; int sum[N]; long long dis[N]; inline void clear() { for(int i=1;i<=n+m;i++) v[i].clear(); while(!q.empty()) q.pop_front(); memset(b,0,sizeof(b)); memset(vis,0,sizeof(vis)); memset(sum,0,sizeof(sum)); memset(dis,999999,sizeof(dis)); } int main() { int T=read(); while(T--) { clear(); n=read();m=read(); for(int i=1;i<n;i++) for(int j=1;j<m;j++) a[i][j]=read(); for(int i=n-1;i>=1;i--) for(int j=m-1;j>=1;j--) b[i][j]=a[i][j]-b[i+1][j]-b[i][j+1]-b[i+1][j+1]; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { int mx=1e6-b[i][j],mn=-b[i][j]; if((i+j)&1) v[j+n].pb(mp(i,-mn)),v[i].pb(mp(j+n,mx)); else v[j+n].pb(mp(i,mx)),v[i].pb(mp(j+n,-mn)); } for(int i=1;i<=n+m;i++) v[0].pb(mp(i,0)); q.push_front(0); dis[0]=0; bool flag=1; while(!q.empty()) { int x=q.front();q.pop_front(); ++sum[x];vis[x]=0; if(sum[x]>n+m){flag=0;printf("NO ");break;} for(int i=0;i<v[x].size();i++) if(dis[v[x][i].first]>dis[x]+v[x][i].second) { dis[v[x][i].first]=dis[x]+v[x][i].second; if(!vis[v[x][i].first]) { if(!q.empty() && dis[v[x][i].first]<dis[q.front()]) q.push_front(v[x][i].first); else q.push_back(v[x][i].first); vis[v[x][i].first]=1; } } } if(!flag) continue; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { if((i+j)&1) b[i][j]-=dis[i]; else b[i][j]+=dis[i]; if((i+j)&1) b[i][j]+=dis[j+n]; else b[i][j]-=dis[j+n]; } printf("YES "); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) printf("%d ",b[i][j]); puts(""); } } return 0; }
后续正在更新ing……