J组:

T1:

没什么好说的。

code:

#include <bits/stdc++.h>

using namespace std;

string s;

int main(){
    cin >> s ;
    int ans=0;
    for(int i=0; i<8; i++)
        if(s[i]=='1')
            ans++;
    cout<<ans;
}

T2:

开一个队列,如果是地铁直接累加答案

是公交就在优惠券的队列找,不断弹出队头

code:


#include <iostream>
#include <cstdio>
#include <queue>

using namespace std;

int n ;

queue < long long > q [100005];

long long ans = 0 ;

int main(){
    cin >> n ;
    int k = 0 ;
    int flag;
    for(int i=1; i<=n; i++){
        int opt , p , t ;
        cin >> opt >> p >> t ;
        if(opt == 0){
            ans += p ;
            q[p] . push (t) ;
            k++ ;
        }
        else{
            int minn = 1e9 + 7 ;
            for(int i=p; i<= 1000; i++){
                while(!q[i].empty()&&q[i].front()+45<t)
                    q[i].pop();
                if(!q[i].empty()){
                    if(minn>q[i].front()){
                        flag=i;
                        minn=q[i].front();
                    }
                }
            }
            if(minn>1e9)
                ans+=p;
            else
                q[flag].pop();
        }

    }
    cout << ans << endl ;
    return 0 ;
}

T3:

T=2提示了完全背包的做法,而你如果观察n=1的情况就会发现每天是独立的,所以只要一维(我考场上写的是正解,然而开了三维,两位没用,连小范围都能爆空间,最后只写了10分送分)

跑T-1次完全背包即可。

code:

#include <bits/stdc++.h>
using namespace std;
int t,n,m,dp[10005],pri[105][105],wl[105],vl[105];
int main () {
    scanf("%d%d%d",&t,&n,&m);
    for (int i=1; i<=t; i++) {
        for (int j=1; j<=n; j++) {
            scanf("%d",&pri[i][j]);
        }
        if (i>=2) {
            memset(dp,0,sizeof(dp));
            for (int j=1; j<=n; j++) {
                wl[j]=pri[i-1][j],vl[j]=pri[i][j]-pri[i-1][j];
                for (int k=wl[j]; k<=m; k++) {
                    dp[k]=max(dp[k],dp[k-wl[j]]+vl[j]);
                }
            }
            int tmp=0;
            for (int j=1; j<=m; j++) {
                tmp=max(tmp,dp[j]+m);
            }
            m=tmp;
        }
    }
    printf("%d\n",m);
    return 0;
}

T4:

占坑...

顺便说一句T3T4都是原题,P2938,P3556 。

S组

Day1:

T1:

07年TG初赛原题

生成公式G(n) = B(n)^B(n+1)

code:

#include <iostream>

using namespace std;

unsigned long long n , k ;

int main(){
    cin >> n >> k ;
    k ^= k >> 1 ;
    while(n--)
        cout << (k>>n&1);
    return 0 ;
} 

T2:

重点讲解:

其实这题用到了kmp的思想

记l为失配数组,即当前节点上一个未被匹配的左括号

cnt是单个节点产生的贡献

ans为节点到根的贡献值和

先考虑链上做法

对于i ,继承l[i]=l[i-1],cnt[i]=cnt[i-1]

如果它是左括号,由于后面的情况未知,l[i] = i ;

如果它是右括号:

前面没有失配的括号,那它不产生任何贡献,跳过

否则 ,匹配两个括号, 让失配数组跳回失配位置-1所对应的的失配位置 , 该点产生的贡献即为其失配位置-1的贡献+1(这两个匹配括号又产生1个贡献)

累加ans

code:

for(int i=1; i<=n; i++) {
        l[i] = l[ i - 1 ] , ans[i] = ans[ i - 1 ] ;
        if(s[i]=='(')
            l[i] = i ;
        else {
            if( s[i] == ')' && l[i] ) {
                cnt[i] = cnt[  l[i]  -1 ] + 1 ;
                l[i] = l[ l[i] - 1 ]  ;
                ans[i] += cnt[i] ;
            }
        }
        ......
    }

注:代码是写blog时临时写的,可能有误,请谨慎食用

这个做法有什么好处:

1:容易理解

2:码量小(大部分都写的dfs)

3:便于扩展

树上做法:

只需将继承,转移时的i-1替换成father[i]

完整代码:

#include <iostream>

#include <cstdio>

using namespace std;

#define ll long long

ll n , f[500005] , ans[500005] , sum ;

ll l[500005] , cnt[500005] ;

char s[500005] ;

int main() {
    cin >> n ;
    cin >> s + 1 ;
    for(int i=2; i<=n; i++)
        cin >> f[i] ;
    for(int i=1; i<=n; i++) {
        l[i] = l[ f[i] ] , ans[i] = ans[ f[i] ] ;
        if(s[i]=='(')
            l[i] = i ;
        else {
            if( s[i] == ')' && l[i] ) {
                cnt[i] = cnt[ f[ l[i] ] ] + 1 ;
                l[i] = l[ f[ l[i] ] ]  ;
                ans[i] += cnt[i] ;
            }
        }
        sum ^= ( ans[i] ) * ( ll ) ( i ) ;
    }
    cout << sum << endl ;
}

本题总结:

独立完成此题,可以加深链上问题扩展到树上一类问题的理解,想出优秀简短的做法

T3:

Day2:

T1:

02-10 16:05