2019杭电多校第三场

HDU-6608

/***
1006 Fansblog HDU-6608 
 
题意:给一个1e9-1e14的质数p,求一个Q!mod p的值,Q为小于p的最大质数
 
思路:威尔逊定理变形得到x!%y=1/(y-x-1)%mod;
	y,x为2个连续的素数且y>x;由素数分布密度可知,y与x不会太远。
	中间还涉及逆元需要处理。
 
***/ 
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll p;
void exgcd(ll a, ll b, ll &x, ll &y) {
    if (b == 0) {
        x = 1;y = 0;
    } else {
        exgcd(b, a%b, y, x);
        y -= (a/b) * x;
    }
}


ll inv(ll a) {
    ll x,y;
    exgcd(a,p,x,y);
    x=(x%p+p)%p;
    printf("%lld\n",x);
}



bool judge(ll x)
{
    for(ll i=2;i*i<=x;i++)
    {
        if(x%i==0)return 0;
    }
    return 1;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld",&p);
        for(ll i=p-1;;i--)
        {
            if(judge(i))
            {
                ll ind=p-i-1;
                ll res=1ll;
                for(ll i=1;i<=ind;i++)res=res*i,res%=p;
                inv(res);
                break;
            }
        }
    }
    return 0;
}

HDU-6609

/*****
1007 Find the answer HDU 6609

题目大意:n个数,对于前i-1个数,剔除多少个数就能使剩余的数求和小于等于m-a[i]

解题思路:将n个数进行离散化,线段树维护一个sum表示区间和,一个num表示当前叶子节点之前有几个比他还
小的数,然后对于每次询问,查询m-a[i],如果大于当前sum,则遍历左子树跟右子树,否则查询值-=sum,然
后return,直到遇到叶子节点,并且叶子节点sum>当前查询值,返回该节点num-1,表示需要剔除
i-1-(num-1)个数,然后把a[i]加到树中,更新num即可

总结:比赛当时用优先队列去写这个题,由于极限样例需要多次push跟pop导致超时 
*****/
#include<bits/stdc++.h>
using namespace std;
#define ll long long

const ll maxn = 2e6+5;
bool flag;

struct TREE
{
    #define lson rt<<1
    #define rson rt<<1|1
    struct Tree{
        ll l,r,num,lazy;
        ll sum;
        ll mid(){ return (l+r)>>1; }
        ll len(){ return r-l+1; }
    }tree[maxn<<2];
    ll ans;
    void pushdown(ll rt){
        if(tree[rt].lazy){
            tree[lson].lazy += tree[rt].lazy;
            tree[rson].lazy += tree[rt].lazy;
            tree[lson].num += tree[rt].lazy;
            tree[rson].num += tree[rt].lazy;
            tree[rt].lazy = 0;
        }
    }

    void pushup(ll rt){
        tree[rt].sum = tree[lson].sum + tree[rson].sum;
    }

    void build(ll l, ll r, ll rt){
        tree[rt].l=l;tree[rt].r=r;
        tree[rt].sum = tree[rt].num = tree[rt].lazy = 0;
        if(l == r) return ;
        ll m = tree[rt].mid();
        build(l,m,lson);
        build(m+1,r,rson);
    }

    void update_sum(ll val, ll pos, ll rt){
        if(tree[rt].l == tree[rt].r && tree[rt].l == pos){
            tree[rt].sum = val;
            return ;
        }
        pushdown(rt);
        //if(tree[rt].l == tree[rt].r) return ;
        ll m = tree[rt].mid();
        if(pos <= m) update_sum(val, pos, lson);
        else update_sum(val, pos, rson);
        pushup(rt);
    }

    void update_num(ll val, ll l, ll r, ll rt){
        if(tree[rt].l == l && tree[rt].r == r){
            tree[rt].lazy += val;
            tree[rt].num += val;
            return ;
        }
        if(tree[rt].l == tree[rt].r) return ;
        pushdown(rt);
        ll m = tree[rt].mid();
        if(r <= m) update_num(val, l, r, lson);
        else if(l > m) update_num(val, l, r, rson);
        else {
            update_num(val, l, m, lson);
            update_num(val, m+1, r, rson);
        }
    }

    ll w;

    void query(ll l,ll r,ll rt){
        if(!flag) return ;
        if(tree[rt].l == tree[rt].r && tree[rt].sum > w && flag){
            ans = tree[rt].num -1;
            flag = false;
            return ;
        }
        pushdown(rt);
        ll m = tree[rt].mid();
        if(w < tree[rt].sum){
            query(l,m,lson);
            query(m+1,r,rson);
        }
        else{
            w -= tree[rt].sum;
            return ;
        }
    }
}myTree;

struct node
{
    ll val,pos,i;
}a[maxn];
ll n,k;

bool cmp1(node x, node y)
{
    return x.val<y.val||(x.val==y.val&&x.pos<y.pos);
}

bool cmp2(node x, node y){
    return x.i<y.i;
}

int main()
{
    ll t;
    scanf("%lld",&t);
    while(t--){
        scanf("%lld%lld",&n,&k);
        for(ll i=1;i<=n;i++){
            scanf("%lld",&a[i].val);
            a[i].i=i;
        }
        sort(a+1,a+1+n,cmp1);
        for(ll i=1;i<=n;i++) a[i].pos=i;
        sort(a+1,a+1+n,cmp2);
        myTree.build(1,n,1);
        for(ll i=1;i<=n;i++){
            myTree.ans = 0;
            flag = true;
            myTree.w = k-a[i].val;
            if(myTree.w < myTree.tree[1].sum) myTree.query(1,n,1),myTree.ans = i-1-myTree.ans;
            myTree.update_sum(a[i].val,a[i].pos,1);
            myTree.update_num(1,a[i].pos,n,1);
            printf("%lld ",myTree.ans);

        }
        puts("");
    }
    return 0;
}

HDU-6611

/*****
1009 K Subsequence HDU 6611 

题意:给定一个n和k,n表示接下来的序列长度,给定序列a,我们可以从这个序列中拿出k个单调不减的子序
列,每次拿了之后可以获得这个子序列的权值和,并且再这之后不能再拿之前拿过的这些数了,求拿了k次之后
得到的最大权值和。

思路:最小费用最大流(也可以最大费用最大流),首先建立源点s和超级源点ss,ss指向s,流为k,花费为
0;然后输入序列的每个ai,将ai割为ai0,ai1两个点,ai0指向ai1,流为1,花费为-ai(用最大费用最大流
的话就改为ai);然后将源点指向每个ai0,流为1,花费为0;将每个ai1指向汇点t,流为1,花费为0;然后
按最长不下降子序列的概念加边:若i>j(1<=i,j<=n),且ai>=aj,aj1指向ai0,流为1,花费为0,最后
MCMF求最小费用最大流(最后的值要取反)。
*****/
#include<bits/stdc++.h>
#define memset0(arr) memset(arr, 0, sizeof(arr))
#define il inline
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int maxn = 1e4;
const int INF = 0x7fffffff;
const int mod = 1e9 + 7;
const double eps = 1e-7;
const double Pi = acos(-1.0);
il int read_int() {
	char c;
	int ret = 0, sgn = 1;
	do { c = getchar(); } while ((c < '0' || c > '9') && c != '-');
	if (c == '-') sgn = -1; else ret = c - '0';
	while ((c = getchar()) >= '0' && c <= '9') ret = ret * 10 + (c - '0');
	return sgn * ret;
}
il ll read_ll() {
	char c;
	ll ret = 0, sgn = 1;
	do { c = getchar(); } while ((c < '0' || c > '9') && c != '-');
	if (c == '-') sgn = -1; else ret = c - '0';
	while ((c = getchar()) >= '0' && c <= '9') ret = ret * 10 + (c - '0');
	return sgn * ret;
}
il ll quick_pow(ll base, ll index) {
	ll res = 1;
	while (index) {
		if (index & 1)res = res * base % mod;
		base = base * base % mod;
		index >>= 1;
	}
	return res;
}
struct edge {
	int to, capacity, cost, rev;
	edge() {}
	edge(int to, int _capacity, int _cost, int _rev) :to(to), capacity(_capacity), cost(_cost), rev(_rev) {}
};
struct Min_Cost_Max_Flow {
	int V, H[maxn + 5], dis[maxn + 5], PreV[maxn + 5], PreE[maxn + 5];
	vector<edge> G[maxn + 5];
	void Init(int n) {
		V = n;
		for (int i = 0; i <= V; ++i)G[i].clear();
	}
	void add(int from, int to, int cap, int cost) {
		G[from].push_back(edge(to, cap, cost, G[to].size()));
		G[to].push_back(edge(from, 0, -cost, G[from].size() - 1));
	}
	int Min_cost_max_flow(int s, int t, int f, int& flow) {
		int res = 0; fill(H, H + 1 + V, 0);
		while (f) {
			priority_queue <pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > q;
			fill(dis, dis + 1 + V, INF);
			dis[s] = 0; q.push(pair<int, int>(0, s));
			while (!q.empty()) {
				pair<int, int> now = q.top(); q.pop();
				int v = now.second;
				if (dis[v] < now.first)continue;
				for (int i = 0; i < G[v].size(); ++i) {
					edge& e = G[v][i];
					if (e.capacity > 0 && dis[e.to] > dis[v] + e.cost + H[v] - H[e.to]) {
						dis[e.to] = dis[v] + e.cost + H[v] - H[e.to];
						PreV[e.to] = v;
						PreE[e.to] = i;
						q.push(pair<int, int>(dis[e.to], e.to));
					}
				}
			}
			if (dis[t] == INF)break;
			for (int i = 0; i <= V; ++i)H[i] += dis[i];
			int d = f;
			for (int v = t; v != s; v = PreV[v])d = min(d, G[PreV[v]][PreE[v]].capacity);
			f -= d; flow += d; res += d*H[t];
			for (int v = t; v != s; v = PreV[v]) {
				edge& e = G[PreV[v]][PreE[v]];
				e.capacity -= d;
				G[v][e.rev].capacity += d;
			}
		}
		return res;
	}
	int Max_cost_max_flow(int s, int t, int f, int& flow) {
		int res = 0;
		fill(H, H + 1 + V, 0);
		while (f) {
			priority_queue <pair<int, int> > q;
			fill(dis, dis + 1 + V, -INF);
			dis[s] = 0;
			q.push(pair<int, int>(0, s));
			while (!q.empty()) {
				pair<int, int> now = q.top(); q.pop();
				int v = now.second;
				if (dis[v] > now.first)continue;
				for (int i = 0; i < G[v].size(); ++i) {
					edge& e = G[v][i];
					if (e.capacity > 0 && dis[e.to] < dis[v] + e.cost + H[v] - H[e.to]) {
						dis[e.to] = dis[v] + e.cost + H[v] - H[e.to];
						PreV[e.to] = v;
						PreE[e.to] = i;
						q.push(pair<int, int>(dis[e.to], e.to));
					}
				}
			}
			if (dis[t] == -INF)break;
			for (int i = 0; i <= V; ++i)H[i] += dis[i];
			int d = f;
			for (int v = t; v != s; v = PreV[v])d = min(d, G[PreV[v]][PreE[v]].capacity);
			f -= d; flow += d;
			res += d*H[t];
			for (int v = t; v != s; v = PreV[v]) {
				edge& e = G[PreV[v]][PreE[v]];
				e.capacity -= d;
				G[v][e.rev].capacity += d;
			}
		}
		return res;
	}
};
int n, k, s1, s2, t, flow, aa[maxn + 5];
Min_Cost_Max_Flow MCMF;
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&k);

        int s=0,t=2*n+2;
        MCMF.Init(t);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&aa[i]);
            MCMF.add(i,i+n,1,-aa[i]);
            MCMF.add(2*n+1,i,1,0);
            MCMF.add(i+n,2*n+2,1,0);
        }
        MCMF.add(s,n*2+1,k,0);
        for(int i=1;i<=n;i++)
        {
            for(int j=i+1;j<=n;j++)
            {
                if(aa[j]>=aa[i])//&&F[j]==F[i]+1
                {
                    MCMF.add(i+n,j,1,0);
                }
            }
        }
        int x=0;
        cout<<-MCMF.Min_cost_max_flow(s,t,INF,x)<<endl;
    }
    return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值