Codeforces Round #174 (Div. 1)(完全)

比赛地址

A:直接贴了个模板,我有罪。。。。

B:dp[i][2],表示从i出发的结果(要么走到挂,要么循环),记忆化搜索就好了,每次要注意判环

C:问你有多少种组合满足Q个条件,每个条件的形式是硬币a出现的次数 大于 硬币b出现的次数  ,先类似于传递闭包搞一下,判掉自己大于自己的情况,然后再用背包来做,每次放进来一个硬币就相当于把出现次数比这个硬币多的硬币都放进来了,由此知道了物品的体积,这是关键所在吧。

#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int N = 310;
const int mod = 1000000007;
int dp[100010] , a[N] , in[N];
int sum[N];
vector<int> edge[N];
bool vis[N];
bool circle;
void dfs(int u)
{
     vis[u] = true; sum[u] = a[u];
     for(int i = 0; i < edge[u].size(); i++){
         int v = edge[u][i];
         if(vis[v]) {
             circle = true;
             return ;
         }
         dfs(v);
         sum[u] += sum[v];
     }
}
bool zero[N];
int main()
{
    circle = false;
    int n , q , t , x , y;
    scanf("%d%d%d",&n,&q,&t);
    fill(zero,zero+n+1,true);
    for(int i = 0; i < n; i++)  scanf("%d",&a[i]);
    for(int i = 0; i < q; i++)
    {
        scanf("%d%d",&x,&y);  x--; y--;
        edge[y].push_back(x);
        zero[x] = false;
        in[x]++;
    }
    for(int i = 0; i < n; i++) if(!in[i])  dfs(i);
    for(int i = 0; i < n; i++)  if(!vis[i]) circle = true;
    if(circle) { return puts("0") , 0;  }
    dp[0] = 1;
    for(int i = 0;i < n; i++) {
        if(!zero[i]) { //必须放一次
            for(int j = t; j >= 0 ; j--) {
                if(j>=sum[i])dp[j] = dp[j-sum[i]];
                else dp[j] = 0;//小于sum[i]的都是非法状态
            }
        }
        for(int j = sum[i]; j <= t; j++) {
            dp[j] += dp[j-sum[i]];
            dp[j] %= mod;
        }
    }
    printf("%d\n",dp[t]);
    return 0;
}



D : 题意:如果x 能表示成连续的y个数之和,那么x 和y就是cool的,现在给你一个最长为5000的序列,问你最少改变几个数字使得整串序列是cool的,整串序列是cool的当且仅当每两个相邻的数是cool的。

5000的范围暗示了是个5000*5000的dp,所以我们只需要解决这样一个问题,给你ai aj,判断这两个数能否成为一个cool序列的头和尾,序列长度为j-i+1.

写了一个证明,英文不好不要吐槽


E数据结构题,给你n个数(代表n值奶牛的力量值),保证每个数唯一,力量大的奶牛可以战胜力量小的奶牛,现在有m个操作,xi yi,每次将力量值在xi,yi区间内的奶牛的比赛结果互换,也就是原来强的变成弱的,相当于异或,强弱互换,最后问题满足(a>b>c>a)这样的(a,b,c)三元组有多少个。

首次碰到这种题,没什么想法,看了题解后立刻联想到以前也有一个题的离线操作方式是类似的,codeforces 157 div1 的E题 ,果然还是太水了,不过div1的E题,从来就没敢打开过。。。。

这题是反着做,如果所有的操作更新完成后,a > b && a > c这种肯定不在解集中,而其他的肯定都在解集中,所以求出所有a >b && a>c的种数就好了。

注意到如果枚举i为最大值,更新 i以后的区间,或者更新i以前的区间(都不包括i),都不会改变其他数与i的关系(大的还是大,小的还是小),所以我们应该想一种方法,使得每次线段树中覆盖的都是与i有关的询问操作区间,写法比较简单的方法是这样的: 离线记录两种区间,一种以i开头,一种以i结尾,更新到i的时候,将以i开头的所有区间都作用到线段树里,统计完结果后将以i结尾的区间都删掉,这样的话,每次询问的时候对线段树产生作用的区间就只剩与i有关的啦。每次查询比i小的数的时候是i(左边的0的个数)+(右边的1的个数),初始时线段树中都是0,覆盖一次就变成了1(取异或)。

http://codeforces.com/contest/283/submission/3363390

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值