【noip2014】day1

T1

[模拟]

找循环节直接模拟即可。

 【code】

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define File "rps"
inline void file(){
    freopen(File".in","r",stdin);
    freopen(File".out","w",stdout);
}
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<<1)+(x<<3)+ch-'0'; ch=getchar();}
    return x*f;
}
const int MAXN = 200 + 10;
int n, na, nb, a[MAXN], b[MAXN], cnta, cntb;
int vs[5][5] = {{0,0,1,1,0},{1,0,0,1,0},{0,1,0,0,1},{0,0,1,0,1},{1,1,0,0,0}}; //得分表的处理
int main(){
    file();
    n = read(),na = read(),nb = read();
    for(int i = 0;i < na; ++i) a[i] = read();
    for(int i = 0;i < nb; ++i) b[i] = read(); 
    for(int i = 0; i < n; i++){
        cnta += vs[a[i % na]][b[i % nb]]; //周期循环
        cntb += vs[b[i % nb]][a[i % na]];
    }
    printf("%d %d\n",cnta,cntb);
    return 0;
}
View Code

 

 

T2

[搜索?]

题意实际上就是要找到(a,b,c)满足a对b连边,b对c连边,求出树上所有这样的三元组的组数的联合权值,以及最大的联合权值。

我们只需枚举中间点是哪一个。

然后遍历它的所有出边,统计答案即可。

还要记得开longlong

求和可能会炸int

 【code】

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define File "link"
inline void file(){
    freopen(File".in","r",stdin);
    freopen(File".out","w",stdout);
}
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<<1)+(x<<3)+ch-'0'; ch=getchar();}
    return x*f;
}
const int mxn = 2e5 + 10;
const int mod = 10007;
int n;
int w[mxn];
struct edge{
    int nxt,y;
}e[mxn<<1]; 

int to[mxn],len;
inline void add(int xx,int yy){
    e[++len].nxt = to[xx];
    to[xx] = len;
    e[len].y = yy;
}

int main(){
    file();
    n = read();
    for(int i = 1;i < n; ++i){
        int x = read(),y = read();
        add(x,y),add(y,x);
    }
    for(int i = 1;i <= n; ++i) w[i] = read();

    ll mx1(0),s1(0);
    ll mx2(0),s2(0);
    
    for(int x = 1;x <= n; ++x){
        s2 = mx2 = 0;    
        for(int i = to[x]; i;i = e[i].nxt){
            int y = e[i].y;
            s1 = (s1 + 1ll*s2*w[y]) % mod;
            mx1 = max(mx1,1ll*mx2*w[y]);
            s2 = (s2 + (ll)w[y]) % mod;
            mx2 = max(mx2,(ll)w[y]);
        }
    }
    printf("%lld %lld\n",mx1,s1*2%mod);    
        
    return 0;
}
/*
5
1 2
2 3
3 4
4 5
1 5 2 3 10
*/
    
View Code

 

 

T3

[dp]

本题主要考虑的是如何满足水管在的情况。

F[i][j]表示横坐标为i,竖直距离为j的最少点击次数。

F[i][j] = min(f[i-1][j-x[i]],f[i][j-x[i]])+1;

F[i][j] = min(f[i][j],f[i-1][j+y[i]]);

如何保证不超过上下边界通过水管?

Dp值更新完之后,在边界以外的dp值赋为正无穷就好了。

由于能够转移而来的初值有限。所以f[0][i] = 0外其余均为正无穷。

 【code】

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf f[0][0]
#define File "bird"
inline void file(){
    freopen(File".in","r",stdin);
    freopen(File".out","w",stdout);
}
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<<1)+(x<<3)+ch-'0'; ch=getchar();}
    return x*f;
}
const int mxn = 1e4 + 5;
const int mxm = 2e3 + 5;
int n,m,k;
int x[mxn],y[mxn];

bool v[mxn];
int l[mxn],h[mxn];
//每个位置可以飞到的上下界。 

int f[mxn][mxm];
//横坐标为i高度为j的最少点击次数。 

inline int min_(int x,int y){
    return x > y ? y : x;
}

int main(){
    file();
    n = read(),m = read(),k = read();
    for(int i = 1;i <= n; ++i) 
        x[i] = read(),y[i] = read(),l[i] = 1,h[i] = m;

    memset(v,0,sizeof v); 
    for(int i = 1;i <= k; ++i){
        int p = read(),a = read(),b = read();
        l[p] = a+1, h[p] = b-1;
        v[p] = 1;
    }    

    memset(f,0x3f,sizeof f);
    for(int i = 1;i <= m; ++i) f[0][i] = 0; //初值 

    for(int i = 1;i <= n; ++i){
        for(int j = x[i]+1;j <= x[i]+m; ++j)
            f[i][j] = min_(f[i-1][j-x[i]],f[i][j-x[i]])+1;
        
        for(int j = m+1;j <= x[i]+m; ++j)
            f[i][m] = min_(f[i][m],f[i][j]); 
        
        for(int j = 1;j <= m-y[i]; ++j)
            f[i][j] = min_(f[i][j],f[i-1][j+y[i]]);
    
        for(int j = 1;j < l[i]; ++j)    f[i][j] = inf;
        for(int j = h[i]+1;j <= m; ++j)    f[i][j] = inf;            
    }

    int ans = inf;
    for(int i = 1;i <= m; ++i) ans = min_(ans,f[n][i]);
    if(ans < inf){
        puts("1");
        printf("%d\n",ans);
        return 0;
    }
    puts("0");
    bool f_ = 1;

    int i,j;    
    for(i = n;i >= 1; --i){
        for(j = 1;j <= m; ++j){
            if(f[i][j] < inf) {
                break;
            }
        }
        if(j <= m) break;    
    }
    ans = 0;
    for(int j = 1;j <= i; ++j)
        if(v[j]) ans++;
        
    printf("%d\n",ans);
    return 0;
}

/*
10 10 4
1 2
3 1
2 2
1 8
1 8
3 2
2 1
2 1
2 2
1 2
1 0 2
6 7 9
9 1 4
3 8 10
*/
View Code

 

posted @ 2019-08-17 11:11  ve-2021  阅读(139)  评论(0编辑  收藏  举报