2019-1005至1007总结
咕的太多了,赶紧补补。
前面的就写写题解,最近的再写总结。
10/05$Night$
T1
模拟,我采取的方法是记录方向和尾部节点。
但是如果使用$vector$记录路径最后$clear$或是直接用$map$会好一些。
我用了一个二维数组,于是T掉了。
后来考完后把数组开小后AC
没人需要代码吧……
还是放一个:
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <vector> #define N 601 #define isv(i,j) visn[(i)+N][(j)+N] using namespace std; int visn[2*N][2*N],ans=0; vector<pair<int,int> >poss; struct BLOCK{ int edx,edy,dir,len;//dir=0(N),1(S),2(W),3(E),-1(U) void getpos(){ poss.clear(); switch(dir){ case 0://N↑ for(int i=0;i<len;i++) poss.push_back(make_pair(edx,edy+i)); break; case 1://S↓ for(int i=0;i<len;i++) poss.push_back(make_pair(edx,edy-i)); break; case 2://W← for(int i=0;i<len;i++) poss.push_back(make_pair(edx-i,edy)); break; case 3://E→ for(int i=0;i<len;i++) poss.push_back(make_pair(edx+i,edy)); break; default:poss.push_back(make_pair(edx,edy)); } } void updatevis(){ switch(dir){ case 0://N↑ for(int i=0;i<len;i++) isv(edx,edy+i)++; break; case 1://S↓ for(int i=0;i<len;i++) isv(edx,edy-i)++; break; case 2://W← for(int i=0;i<len;i++) isv(edx-i,edy)++; break; case 3://E→ for(int i=0;i<len;i++) isv(edx+i,edy)++; break; default:isv(edx,edy)++; } } void clear(){ this->edx=this->edy=0; this->dir=-1; this->updatevis(); } void move(const char mq){ switch(mq){ case 'N'://0↑ if(this->dir==-1){ this->edy++; this->dir=0; } else if(this->dir==2 || this->dir==3)//W E this->edy++; else{ if(this->dir==0)//N this->edy+=this->len; else//S this->edy++; this->dir=-1;//Up } break; case 'S'://1↓ if(this->dir==-1){ this->edy--; this->dir=1; } else if(this->dir==2 || this->dir==3)//W E this->edy--; else{ if(this->dir==0)//N this->edy--; else//S this->edy-=this->len; this->dir=-1;//Up } break; case 'W'://2← if(this->dir==-1){ this->edx--; this->dir=2; } else if(this->dir==0 || this->dir==1)//N S this->edx--; else{ if(this->dir==2)//W this->edx-=this->len; else//E this->edx--; this->dir=-1; } break; case 'E'://3→ if(this->dir==-1){ this->edx++; this->dir=3; } else if(this->dir==0 || this->dir==1)//N S this->edx++; else{ if(this->dir==3)//E this->edx+=this->len; else//W this->edx++; this->dir=-1; } break; default:puts("Error A Wrong Move"); } this->updatevis(); } void pour(){ cout<<"("<<this->edx<<","<<this->edy<<")"; switch(this->dir){ case -1: puts("⊡"); break; case 0://N puts("↑"); break; case 1: puts("↓"); break; case 2: puts("←"); break; case 3: puts("→"); break; default: puts("A Error In \'dir\'"); } } }bl; int cn; char st[N]; int main(){ // freopen("block.in" ,"r",stdin); // freopen("block.out","w",stdout); int T; cin>>T; while(T--){ memset(visn,0,sizeof visn); memset(st,0,sizeof st); bl.clear(); ans=0; scanf("%d%s",&bl.len,st+1); for(int i=1;st[i]!=0;i++) bl.move(st[i]);//bl.pour(); bl.getpos(); sort(poss.begin(),poss.end()); for(int i=0;i<poss.size();i++) printf("%d ",poss[i].first); puts(""); for(int i=0;i<poss.size();i++) printf("%d ",poss[i].second); puts(""); for(int i=-600;i<=600;i++) for(int j=-600;j<=600;j++) ans=max(ans,isv(i,j)); printf("%d\n",ans); } }
T2
毒瘤数学题,不会……咕咕咕。
T3
新思路:把一段操作压成一个$hash$值
或者靠这个题的特性,维护值域区间。
于是线段树区间乘,区间加。
代码撂着:
#include <iostream> #include <cstring> #include <cstdio> #define N 222222 #define LL long long using namespace std; const int Mod=1995667591,Upbit=333667; struct XDS{ int l,r; LL add,muilt; #define lc(k) ((k)<<1) #define rc(k) (((k)<<1)|1) }rt[4*N]; int dn,cn,clt; LL clhs=0; void build(int k,int l,int r){//cout<<k<<" + "<<l<<" + "<<r<<endl; rt[k].l=l,rt[k].r=r; rt[k].add=0; rt[k].muilt=1; if(l==r) return ; int mid=(l+r)>>1; build(lc(k),l ,mid); build(rc(k),mid+1,r); } void downlazy(int k){ if(rt[k].l!=rt[k].r){ if(rt[k].muilt!=1){ rt[lc(k)].muilt=(rt[lc(k)].muilt*rt[k].muilt)%Mod; rt[rc(k)].muilt=(rt[rc(k)].muilt*rt[k].muilt)%Mod; rt[lc(k)].add =(rt[lc(k)].add *rt[k].muilt)%Mod; rt[rc(k)].add =(rt[rc(k)].add *rt[k].muilt)%Mod; rt[k].muilt=1; } if(rt[k].add){ rt[lc(k)].add=(rt[lc(k)].add+rt[k].add)%Mod; rt[rc(k)].add=(rt[rc(k)].add+rt[k].add)%Mod; rt[k].add=0; } } } void add(int k,int l,int r,LL v){//cout<<"-----------------------------------------------------\nAdd:"<<k<<endl \ <<"RTL:"<<rt[k].l<<endl \ <<"RTR:"<<rt[k].r<<endl \ <<"QEL:"<<l<<endl \ <<"QER:"<<r<<endl \ <<"QRV:"<<v<<endl; if(l<=rt[k].l && rt[k].r<=r){ rt[k].add=(v+rt[k].add)%Mod; return ; } if(rt[k].l==rt[k].r)return ; downlazy(k); int mid=(rt[k].l+rt[k].r)>>1; if(l<=mid) add(lc(k),l,r,v); if(r>mid) add(rc(k),l,r,v); } void muilt(int k,int l,int r,LL v){//cout<<"===================================================\nMuilt:"<<k<<endl \ <<"RTL:"<<rt[k].l<<endl \ <<"RTR:"<<rt[k].r<<endl \ <<"QEL:"<<l<<endl \ <<"QER:"<<r<<endl \ <<"QRV:"<<v<<endl; if(l<=rt[k].l && rt[k].r<=r){ rt[k].add =(v*rt[k].add)%Mod; rt[k].muilt=(v*rt[k].muilt)%Mod; return ; } if(rt[k].l==rt[k].r)return ; downlazy(k); int mid=(rt[k].l+rt[k].r)>>1; if(l<=mid) muilt(lc(k),l,r,v); if(r>mid) muilt(rc(k),l,r,v); } int getans(int k){ if(rt[k].l==rt[k].r){ //cout<<k<<"----"<<rt[k].add<<"("<<clhs<<")"<<endl; return rt[k].add==clhs; } downlazy(k); return getans(lc(k))+getans(rc(k)); } int main(){ int a,b,c; scanf("%d%d%d",&dn,&clt,&cn); build(1,1,dn); for(LL i=1;i<=clt;i++) clhs=((clhs*Upbit)+i)%Mod; for(int i=1;i<=cn;i++){ scanf("%d%d%d",&a,&b,&c); muilt(1,a,b,Upbit); add (1,a,b,c); } printf("%d\n",getans(1)); }
10/06
Codeforces & AtCoder
T1-(Codeforces Round #434 Div. 1)D. Wizard's Tour
<题目链接>
题目被翻译了,还被改名了 ??
不管了。
这是虎的加强版。
贪心。在图上DFS,形成一棵搜索树。
那么可以把边分为鸡肋几类
不是通向父节点的两两配对,
通向父节点的分类讨论,和下面剩下的配,其次贡献给父节点
这样贪心的结果是可以保证的,最多只有根节点有一条边被浪费。
#include <iostream> #include <cstring> #include <cstdio> #include <vector> #define M 222222 #define N 222222 using namespace std; struct SR{ int next,t; bool is_des,is_tr; SR(){next=t=is_des=is_tr=0;} }rs[2*M]; int pn, edn, cnt=0, fl[N], deg[N]; bool is_v[N], usdfa[N]; struct ANS{ int f,m,t; ANS(int a,int b,int c):f(a),m(b),t(c){} }; vector<ANS>ans; void add(int f,int t){ rs[cnt].t=t; rs[cnt].next=fl[f]; fl[f]=cnt++; } void dfs(int k,int pre,int pp){//cout<<k<<"<-"<<pp<<endl; is_v[k]=1; int ls=0,lstid; if(pre!=-1)rs[pre].is_tr=rs[pre^1].is_tr=1; for(int i=fl[k];i!=-1;i=rs[i].next){ int t=rs[i].t; if(rs[i].is_des || t==pp)continue; if(!is_v[t]){ dfs(t,i,k); if(!usdfa[t])deg[k]++; else continue; } else if(!rs[i].is_tr) deg[k]++; if(ls){ ans.push_back(ANS(ls,k,t)); rs[lstid ].is_des=\ rs[lstid^1].is_des=\ rs[i] .is_des=\ rs[i^1] .is_des=1; ls=0; } else { ls=t; lstid=i; } } if(pre==-1)return ; if(deg[k]&1){ usdfa[k]=1; if(ls!=0){ rs[pre ].is_des=\ rs[pre^1].is_des=\ rs[lstid].is_des=\ rs[lstid^1].is_des=1; ans.push_back(ANS(pp,k,ls)); } } } int main(){ int a,b; //freopen("1.in","r",stdin); memset(fl,-1,sizeof fl); scanf("%d%d",&pn,&edn); for(int i=1;i<=edn;i++){ scanf("%d%d",&a,&b); add(a,b); add(b,a); } for(int i=1;i<=pn;i++){ if(!is_v[i]){ dfs(i,-1,-1); } } printf("%d\n",ans.size()); for(int i=0;i<ans.size();i++) printf("%d %d %d\n",ans[i].f,ans[i].m,ans[i].t); }
T2-AtCoder Grand Round #1 F.Wide Swap
<题目链接>
序列神题。
用拓扑维护数之间的不变关系。
加上线段树优化建图。
没有过$QAQ$
T3-Codeforces Round #200 Div.1 E Tree ( ? )
说是上面的题,蒟蒻麦蒙在CF官网上翻了半天愣是没有……
结论题,答案就是所有边权之和(%%%出题人)
简单证明一番。
我们想要最大值,于是可以转化为经过最小值的次数最少。
于是把最小值的边经过一次并删除,分成两棵树。
对这两棵树分别进行上述操作就可以得到次小和次次小值。
重复上述操作。可以得出结论,所有的边只会被经过一次。
于是就结束了,至于代码,放一个也行……
#include <cstdio> using namespace std; long long pn,c,ans; int main(){ scanf("%lld",&pn); for(int i=1;i<pn;i++){ scanf("%*d%*d%lld",&c); ans+=c; } printf("%lld\n",ans); }
20191007
总结
时间分配还可以,T3分得有点少了。
所以T3的dp跪了。
得与失
得:
- 想了一些优化手段。
- 打了不同的部分分。
- $dp$的意识(雾
失:
- 又没写对拍。(没正解或是没暴力)
- $dp$的柿子并没有推清楚
结果
25
|
860郭本一 | 50
03:11:03
|
5
03:11:03
|
11
03:13:31
|
66
03:13:31
|
话说$T2$为啥作差不加绝对值啊……
给题解留个坑$\Huge \lfloor\rfloor$
Miemeng真的蒻