佛了佛了,这场模拟卡了三个小时,好不容易碰到一道费用流结果根本没时间写
Problem A CFGym 102801A Micro Structure Thread???
2 / 3 Problem B CFGym 102801B Team !!!
网络流题目的常见套路,源点和b集合连边,b集合和a集合连边,a集合和c集合连边,这样就能保住必选三个人了,注意a集合在中间要拆点自己和自己的副本连一条流量1费用0的边来现在a只用一次
这种套路洛谷上我就见到至少三个,好可惜啊
#include<stdio.h>
#include<vector>
#include<string.h>
#include<queue>
#define ll long long
#define mod 998244353
#define maxn 10033
using namespace std;
const ll inf=1e9;
#include<vector>
struct E
{
ll to,next,lim,cos;
}e[maxn*100];
ll head[maxn],cnt;
void add(ll u,ll v,ll lim,ll cos)
{
e[cnt].to=v;
e[cnt].lim=lim;
e[cnt].cos=cos;
e[cnt].next=head[u];
head[u]=cnt++;
e[cnt].to=u;
e[cnt].lim=0;
e[cnt].cos=-cos;
e[cnt].next=head[v];
head[v]=cnt++;
}
ll n,m,s,t;
queue<ll>q;
ll dis[maxn],flow[maxn],pre[maxn],vis[maxn];
ll bfs()
{
while(!q.empty()) q.pop();
q.push(s);
for(ll i=0;i<=t+10;i++) dis[i]=-inf,flow[i]=inf,vis[i]=0;//注意根据题目更改清空范围
vis[s]=1;dis[s]=0;
while(!q.empty())
{
ll u=q.front();q.pop();
//printf("-u=%lld\n",u);
for(ll i=head[u];i!=-1;i=e[i].next)
{
ll v=e[i].to,w=e[i].cos,lim=e[i].lim;
if(lim>0&&(dis[u]+w>dis[v]))
{
//printf(" v=%lld w=%lld lim=%lld dis[%lld]=%lld dis[%lld]=%lld\n",v,w,lim,u,dis[u],v,dis[v]);
dis[v]=dis[u]+w;
flow[v]=min(flow[u],lim);
//printf("flow[%lld]=%lld flow[%lld]=%lld\n",u,flow[u],v,flow[v]);
pre[v]=i;
if(vis[v]==0)
{
vis[v]=1;
q.push(v);
}
}
}
vis[u]=0;
}
//printf("flow[%lld]=%lld\n",t,flow[t]);
return flow[t]==inf?-1:1;
}
ll slove()
{
ll mxflow=0,micost=0;
while(bfs()==1)
{
micost+=dis[t]*flow[t];
mxflow+=flow[t];
//printf("micost=%lld mxflow=%lld\n",micost,mxflow);
ll v=t;
//printf("111\n");
//printf("v=%lld\n",v);
while(1)
{
ll u=e[pre[v]^1].to;
//printf(" u=%lld\n",u);
e[pre[v]].lim-=flow[t];
e[pre[v]^1].lim+=flow[t];
v=u;
if(u==s) break;
}
}
printf("%lld\n",micost);
}
void init()
{
memset(head,-1,sizeof(head));
cnt=0;
}
ll a[maxn],b[maxn],c[maxn];
int main()
{
int t1;
scanf("%d",&t1);
while(t1--)
{
ll M;
scanf("%lld %lld %lld",&n,&m,&M);
for(ll i=1;i<=n;i++) scanf("%lld",&a[i]);
for(ll i=1;i<=n;i++) scanf("%lld",&b[i]);
for(ll i=1;i<=n;i++) scanf("%lld",&c[i]);
s=0;t=4*n+4;
ll s1=4*n+1;
init();add(s,s1,m,0);
for(int i=1;i<=n;i++)
{
add(s1,i,1,0);
}
for(ll i=1;i<=n;i++)
{
for(ll j=1;j<=n;j++)
{
add(i,n+j,1,(a[j]+b[i])*(a[j]^b[i])%M);
//printf("i=%lld j=%lld w=%lld\n",i,n+j,(a[j]+b[i])*(a[j]^b[i])%M);
}
}
for(ll i=1;i<=n;i++) add(n+i,2*n+i,1,0);
for(ll i=1;i<=n;i++)
{
for(ll j=1;j<=n;j++)
{
add(2*n+i,n*3+j,1,(a[i]+c[j])*(a[i]^c[j])%M);
//printf("i=%lld j=%lld w=%lld\n",2*n+i,3*n+j,(a[i]+c[j])*(a[i]^c[j])%M);
}
}
for(ll i=1;i<=n;i++) add(3*n+i,t,1,0);
slove();
}
/*scanf("%lld %lld %lld %lld",&n,&m,&s,&t);
for(ll i=1;i<=m;i++)
{
ll u,v,w,s;
scanf("%lld %lld %lld %lld",&u,&v,&w,&s);
add(u,v,w,s);
//add(u,v,w);
}*/
//slove();
}
/*
1111
2 2 10
1 9
9 1
10 10
*/
8 / 16 Problem C CFGym 102801C Function---
9 / 18 Problem D CFGym 102801D Fall Guys---
2 / 29 Problem E CFGym 102801E Liner vectors !!!
一道找规律的题目,结果在那里存一万个数乱搞,时间花了还没写出来
题意是找到n个数,这n个数的二进制中的一的个数为k,而且其中一个数不能被其他数异或得到,求字典序最小的n个数
简单讲一下规律,首先k为偶数一定没有答案,如果n要大于c[n][k]也没有答案,一般规律就是假如n为9,k为5,那么答案就为:
000011111
000101111
000110111
000111011
000111101
000111110
001001111
010001111
100001111
对于前k+1个,就是对于一个(k+1)*(k+1)的矩阵,对角线上是0,其他位置都是1
剩下的是对于第2个求得的值,其中第一个1往左移一位
代码
#include<stdio.h>
#include<algorithm>
using namespace std;
#define ll long long
ll ans[100];
ll er[70];
int main(){
er[0]=1;
for(int i=1;i<=63;i++)er[i]=er[i-1]*2ll;
int t;
scanf("%d",&t);
while(t--){
ll n,k;
scanf("%lld %lld",&n,&k);
if(n==1&&k==1){
printf("1\n");
continue;
}
ll z=min(k,n-k);
ll now=1;
int flag=0;
for(ll i=1;i<=z;i++){
now=now*(n-i+1)/i;
if(now>=n){
flag=1;
break;
}
}
if(flag==0){
printf("-1\n");
continue;
}
if(k%2==0||n==k){
printf("-1\n");
continue;
}
ans[1]=er[k]-1;
for(int i=2;i<=min(k+1,n);i++){
ans[i]=er[k+1]-1-er[k-i+1];
}
for(int i=k+2;i<=n;i++){
ans[i]=er[i-1]+er[k-1]-1;
}
for(int i=1;i<=n;i++){
printf("%lld",ans[i]);
if(i==n){
printf("\n");
}
else{
printf(" ");
}
}
}
}
Problem F CFGym 102801F Splendor???
8 / 17 Problem G CFGym 102801G Halli Galli ---
7 / 24 Problem H CFGym 102801H PepperLa's String !!!
队内倒数可还行 这道题人均会写
至于为何卡这题
我想我们对于实现没有想清楚 就开始写了
首先要满足长度最小 其次才是字典序最小
字典序关系 数字<大写字母<小写字母
一开始我们先把所有连续的字母进行压缩(不可能从中间断开 成两端 长度肯定更长)写成字母+数量的形式
那么数量可以减少有三种情况
1.当前字母只有一个 直接删去它
2.当前字母有两个删去一个
3.当前字母大于两个 并且删去一个以后数量表示的十六进制会缩短一位(例如 10->F)
我们先看有没有上述三种的情况 如果没有的话 我们直接删去第一个字母就行
而上述三种情况只有第一种情况 可能让字典序变小(第二种情况在字符串末尾也行 但是我们把他归类为其他情况)那就是当前字母字典序大于后面的字母(或当前字母在最后位置)
对于其他情况来说 因为它们会增大字典序 所以这样的修改放在尽量靠后的位置
综上所述就是
1.如果无法改变数量 就删掉第一个
2.否则 如果是第一类情况 并且可以减小字典序 那么就优先考虑这种
3.其他情况 考虑位置最靠后的那种
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+100;
char s[N],now[N];
int cnt[N];
int trans(int x,int print){
vector<char>q;
while(x){
q.push_back((x%16)>9?(x%16-10+'A'):(x%16+'0'));
x/=16;
}
reverse(q.begin(),q.end());
if(print) for(int j = 0; j < (int)q.size(); j++) printf("%c",q[j]);
return q.size();
}
void solve(){
int len = strlen(s+1),ct = 0,m = 0;
for(int i = 1; i <= len; i++){
if(i==1||s[i]!=s[i-1]){
ct=1;
}else ct++;
if(i==len||s[i]!=s[i+1]){
now[++m]=s[i];
cnt[m]=ct;
}
}
int del_pos=1;
for(int i = 1; i <= m; i++){
if(cnt[i]==1){
del_pos=i;
if(i==m||now[i]>now[i+1]) break;
}
if(cnt[i]==2||trans(cnt[i],0)>trans(cnt[i]-1,0))
del_pos=i;
}
cnt[del_pos]--;
for(int i = 1; i <= m; i++){
if(cnt[i]==0) continue;
if(cnt[i]==1){
printf("%c",now[i]);
continue;
}
printf("%c",now[i]);
trans(cnt[i],1);
}
puts("");
}
int main(){
while(~scanf("%s",s+1)){
solve();
}
return 0;
}
8 / 20 Problem I CFGym 102801I PepperLa's Cram School ---
9 / 13 Problem J CFGym 102801J Color the blocks ---
0 / 2 Problem K CFGym 102801K PepperLa's Boast !!!
容易推出转移方程
dp[i][j]=max(dp[i-1][j-1],dp[i-1][j],dp[i][j-1]) (a[i][j]>0)
dp[i][j]=max(dp[i][j],dp[x][y]-u+a[i][j]) (i-x<=k,j-y<=k)
用二维的单调队列维护即可 比较新颖的用法 一边dp一边维护单调队列
#include<bits/stdc++.h>
using namespace std;
const int N = 1e3+100;
typedef long long ll;
struct node{
ll val;
int id;
};
deque<node>col[N],rol;
ll a[N][N],dp[N][N];
int main(){
int n,m,k,u;
while(~scanf("%d%d%d%d",&n,&m,&k,&u)){
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++){
scanf("%lld",&a[i][j]);
}
memset(dp,-1,sizeof(dp));
dp[1][1]=a[1][1];
for(int i = 1; i <= m; i++) col[i].clear();
for(int i = 1; i <= n; i++){
rol.clear();
for(int j = 1; j <= m; j++){
while(col[j].size()&&col[j].front().id<i-k) col[j].pop_front();
while(rol.size()&&rol.front().id<j-k) rol.pop_front();
if(a[i][j]>0){
if(~dp[i-1][j]) dp[i][j]=max(dp[i][j],a[i][j]+dp[i-1][j]);
if(~dp[i][j-1]) dp[i][j]=max(dp[i][j],a[i][j]+dp[i][j-1]);
if(~dp[i-1][j-1]) dp[i][j]=max(dp[i][j],a[i][j]+dp[i-1][j-1]);
if(col[j].size()){
while(rol.size()&&rol.back().val<=col[j].front().val) rol.pop_back();
rol.push_back((node){col[j].front().val,j});
}
if(rol.size()) dp[i][j]=max(dp[i][j],rol.front().val+a[i][j]-u);
if(col[j].size()) rol.pop_back();
}
if(dp[i][j]>=u){
while(col[j].size()&&col[j].back().val<=dp[i][j]) col[j].pop_back();
col[j].push_back((node){dp[i][j],i});
}
if(col[j].size()){
while(rol.size()&&rol.back().val<=col[j].front().val) rol.pop_back();
rol.push_back((node){col[j].front().val,j});
}
}
}
printf("%lld\n",dp[n][m]);
}
return 0;
}