The 14th Chinese Northeast Collegiate Programming Contest


佛了佛了,这场模拟卡了三个小时,好不容易碰到一道费用流结果根本没时间写

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;
}

0 / 1 Problem L CFGym 102801L PepperLa's Express ???


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM