2018.7.24日记&总结

今天是我们组出题,也做了一下。过了4题,感觉题目难度不大。多想想欧拉路那道题说不定也可以做。还顺带过了不是今天比赛的一道线段树合并。感觉代码能力的确有所提高(算是恢复)。但是离应有的状态还是差很远!
今天的几何题很简单但是没有去写,因为几何的板子太陌生。其实几何的东西不多,只要熟悉几个基本的模型,就比较好做。一定不要期望ACM队里有人帮你写几何题,因此这个假期一定要练好几何!每天至少1道。先把板子敲熟再应用。做到轻松过题。
今天下午和晚上的状态很差,写题效率极低,必须反思!坚持到最后一刻!不能放松!适当的运动后应该静下心来写题!控制住自己!高效的写题!
今天我出的题(虽然不是原创)感觉还是不错的。然而没有人来写,有点小遗憾!
这两天的题还有4道没有调你在干什么,明天必须一起全部调完!!!

题解:
A:推结论。然后暴力。挺显然的,就是思维要放开

B:几何。圆与矩形求交转化成把矩形扩展(四角变成1/4圆)和圆心运动的直线求交。
今天没有写完(打球去了,忘了自己应该做的事!)明天写

C:签到题。WA了两发因为没有看清楚题意。题目上说的是prime number

D:每个位置有pi概率为1,求区间连续1的长度3次方的期望。单点修改。
把dp贡献差分,维护1,2,3次,矩阵快速幂维护转移。利用矩阵的结合律(直接DP无法结合)
经典题

//把f数组维护成贡献增加(前缀和),矩阵快速幂的时候就不用记ans了,优化一维
//线段树维护矩阵,动态DP,经典思想。因为矩阵满足结合律,而直接dp无法统计左边对右边的贡献
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
#define maxn 200020
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define inf 1e8


typedef long long ll;
inline int read(){
    register int num = 0;
    register char ch = getchar();
    while ( ch > '9' || ch < '0' ) ch = getchar();
    while ( ch <= '9' && ch >= '0' ) num = num * 10 + ch - '0' , ch = getchar();
    return num;
}
int num[10];
inline void write(int x){
    register int cnt = 0;
    if ( !x ){ printf("0"); return; } //一定要特判0!!!
    while ( x ) num[++cnt] = x % 10 , x /= 10;
    while ( cnt ) putchar(num[cnt--] + '0');
}
double a[4][4],b[4][4],tmp[4][4],p[maxn],mtx[maxn][4][4];
int ls[maxn],rs[maxn],tot,root;
int n,m,T;

void clear(){
    rep(i,0,tot) memset(mtx[i],0,sizeof(mtx[i])) , ls[i] = rs[i] = 0;
    tot = root = 0;
}
inline void power(double a[4][4],double b[4][4],double c[4][4]){
    memset(tmp,0,sizeof(tmp));
//rep(i,0,4) rep(j,0,4) tmp[i][j] = 0;
    rep(i,0,3) rep(j,0,3) rep(k,0,3) tmp[i][j] += b[i][k] * c[k][j];
    memcpy(a,tmp,sizeof(tmp));
}
void update(int x){
    power(mtx[x],mtx[ls[x]],mtx[rs[x]]);
}
void build(int &x,int l,int r){
    x = ++tot;
    if ( l == r ){
        mtx[x][1][1] = mtx[x][2][2] = mtx[x][0][3] = mtx[x][1][3] = mtx[x][2][3] = p[l];
        mtx[x][0][1] = mtx[x][0][2] = p[l] * 3 , mtx[x][1][2] = p[l] * 2;
        mtx[x][0][0] = mtx[x][3][3] = 1;
        return;
    }
    int mid = (l + r) >> 1;
    build(ls[x],l,mid) , build(rs[x],mid + 1,r);
    update(x);
}
void modify(int x,int l,int r,int id,double cp){
    if ( l == r ){
        p[l] = cp;
        mtx[x][1][1] = mtx[x][2][2] = mtx[x][0][3] = mtx[x][1][3] = mtx[x][2][3] = p[l];
        mtx[x][0][1] = mtx[x][0][2] = p[l] * 3 , mtx[x][1][2] = p[l] * 2;
        mtx[x][0][0] = mtx[x][3][3] = 1;
        return;
    }
    int mid = (l + r) >> 1;
    if ( id <= mid ) modify(ls[x],l,mid,id,cp);
    else modify(rs[x],mid + 1,r,id,cp);
    update(x);
}
void query(int x,int l,int r,int L,int R,double a[4][4]){
    if ( L <= l && R >= r ) { power(a,a,mtx[x]); return; }
    int mid = (l + r) >> 1;
    if ( L <= mid ) query(ls[x],l,mid,L,R,a);
    if ( R > mid ) query(rs[x],mid + 1,r,L,R,a);
}
int main(){
//  freopen("input.txt","r",stdin);
    scanf("%d",&T);
    while ( T-- ){
        clear();
        scanf("%d",&n);
        rep(i,1,n) scanf("%lf",&p[i]);
        build(root,1,n);
        scanf("%d",&m);
        while ( m-- ){
            int tp,x,l,r; double cp;
            scanf("%d",&tp);
            if ( tp == 1 ){
                scanf("%d %lf",&x,&cp); 
                modify(root,1,n,x,cp);
            }
            else{
                scanf("%d %d",&l,&r);
                memset(a,0,sizeof(a));
                rep(i,0,3) a[i][i] = 1;
                query(root,1,n,l,r,a); 
                double ans = a[0][3];
                printf("%.2f\n",ans);
            }
        }
    }
    return 0;
}

E:一道欧拉回路的好题。[1,m]的数各出现n次,每次与0交换(开始0在末尾)使[k * m + 1,k *m + m]的区间中[1,m]恰好各出现一次。
对于每一个区间,如果一个值多了则向该数连边,少了则该数向它连边。对于每个联通块找欧拉回路。因为出入度相等所以一定存在。
输出方案在欧拉回路退栈的时候推下细节。非常好写。但是因为看错数据范围调了很久!很不应该!
求欧拉回路要边要dfs完后加入栈,保证边的顺序

//看清数据范围再写题!!!
#include<bits/stdc++.h>
using namespace std;
#define maxn 820
#define N 200020
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define inf 1e8

struct node{
    int next,to,from;
}e[N];
struct node2{
    int x,y;
};
int head[maxn],cnt;
int n,m,T,stack_[N],tops,tag[N];
int a[maxn][maxn],num[maxn][maxn],tmp,vis[maxn];
vector <int> vec[maxn][maxn];
vector <node2> ans;

void clear(){
    rep(i,1,n + m) vis[i] = head[i] = 0;
    rep(i,1,n) rep(j,1,m) num[i][j] = 0 , vec[i][j].clear();
    rep(i,1,cnt) tag[i] = 0;
    ans.clear(); cnt = 0;
}
inline void adde(int x,int y){
    e[++cnt].to = y;
    e[cnt].next = head[x];
    e[cnt].from = x;
    head[x] = cnt;
}
void dfs(int x){
    vis[x] = 1;
    for (int i = head[x] ; i ; i = e[i].next){
        if ( tag[i] ) continue;
        tag[i] = 1;
        dfs(e[i].to);
        stack_[++tops] = i; //求欧拉回路要后加入栈,保证边的顺序
    }
}
int main(){
    freopen("input.txt","r",stdin);
    freopen("1.out","w",stdout);
    while ( ~scanf("%d %d",&n,&m) ){
        tmp = n * m + 1;
        rep(i,1,n){
            rep(j,1,m) scanf("%d",&a[i][j]) , vec[i][a[i][j]].push_back((i - 1) * m + j) , num[i][a[i][j]]++;
            rep(j,1,m){
                if ( !num[i][j] ) adde(j,m + i);
                else rep(k,2,num[i][j]) adde(m + i,j);
            }
        }
        rep(i,m + 1,n + m){
            if ( !vis[i] ){
                int fir = head[i],id,cur,last,num;
                tops = 0 , dfs(i);
                if ( !fir ) continue;
                last = vec[i - m][e[fir].to].back();
                vec[i - m][e[fir].to].pop_back();
                ans.push_back((node2){last,tmp});
                for(int j = 1 ; j <= tops ;j++){
                    id = stack_[j], num = e[id].from;
                    id = stack_[++j];
                    if ( j == tops ) cur = n * m + 1;   
                    else{
                        cur = vec[e[id].from - m][num].back();
                        vec[e[id].from - m][num].pop_back();    
                    }
                    ans.push_back((node2){last,cur});
                    last = cur;
                }
            }
        }
        printf("%d\n",ans.size());
        for (int i = 0 ; i < ans.size() ; i++){
            printf("%d %d\n",ans[i].x,ans[i].y);
        }
        clear();
    }
    return 0;
}

F:求最少删多少个数是最长上升子序列变短。
按f[i](dp值)分层建图。最小割。
好久没写网络流的题。考场上现场yy出来的。
但是应该加强网络流的练习,别把强项丢了

G:我自己的题。见我的出题日志。

最后,提醒几点:
1。早点睡,保证考试时精力充沛!
2。一定要复习,有10多天没有复习以前的题了
3。坚持到最后一刻,一直到开学都不能有一点松懈。把自己的弱项静心补起来,相信自己OI的实力!
4。明天打好翻盘仗!静下心来思考!争取过5题!进入前5名!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章