2020EC-final
傳送門
文章目錄
- B - Rectangle Flip 2
- 題意:
- 思路:
- A - Namomo Subsequence
- 題意:
- 思路:
- D - City Brain
- 題意:
- 思路:
B - Rectangle Flip 2
題意:
給你一個(gè)n?mn*mn?m的矩陣,接下來n?mn*mn?m秒每秒都會(huì)消失一個(gè)格子,問每個(gè)時(shí)刻矩陣中構(gòu)成的矩形有多少個(gè)。
n,m≤500n,m\le 500n,m≤500
思路:
先說一下復(fù)雜度n4n^4n4但是跑不滿的算法,對(duì)于每個(gè)刪去的點(diǎn),枚舉左邊以及右邊每個(gè)位置,維護(hù)其能到的上下界,比如上界xxx下界yyy,當(dāng)前點(diǎn)是(dx,dy)(dx,dy)(dx,dy),那么答案就是(dx?y+1)?(x?dx+1)(dx-y+1)*(x-dx+1)(dx?y+1)?(x?dx+1),看似n4n^4n4,實(shí)際500ms500ms500ms就跑完了。
還有一個(gè)穩(wěn)定n3n^3n3用單調(diào)棧跑的并沒有看懂代碼是怎么寫的,就先咕咕了。
//#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math") //#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native") //#pragma GCC optimize(2) #include<cstdio> #include<iostream> #include<string> #include<cstring> #include<map> #include<cmath> #include<cctype> #include<vector> #include<set> #include<queue> #include<algorithm> #include<sstream> #include<ctime> #include<cstdlib> #define X first #define Y second #define L (u<<1) #define R (u<<1|1) #define pb push_back #define mk make_pair #define Mid (tr[u].l+tr[u].r>>1) #define Len(u) (tr[u].r-tr[u].l+1) #define random(a,b) ((a)+rand()%((b)-(a)+1)) #define db puts("---") using namespace std;//void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); } //void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); } //void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }typedef long long LL; typedef unsigned long long ULL; typedef pair<int,int> PII;const int N=510,mod=1e9+7,INF=0x3f3f3f3f; const double eps=1e-6;int n,m; int D[N][N],U[N][N]; int st[N][N];int main() { // ios::sync_with_stdio(false); // cin.tie(0);scanf("%d%d",&n,&m);for(int i=1;i<=n;i++) {for(int j=1;j<=m;j++){D[i][j]=n+1;U[i][j]=0;}}LL ans=1ll*n*(n+1)*m*(m+1)/4;for(int i=1;i<=n*m;i++) {int x,y; scanf("%d%d",&x,&y);for(int l=y,u1=0,d1=n+1;l>=1&&!st[x][l];l--) {u1=max(u1,U[x][l]+1);d1=min(d1,D[x][l]-1);for(int r=y,u2=u1,d2=d1;r<=m&&!st[x][r];r++) {u2=max(u2,U[x][r]+1);d2=min(d2,D[x][r]-1);ans-=1ll*(x-u2+1)*(d2-x+1);}}for(int j=x;j<=n;j++) U[j][y]=max(U[j][y],x);for(int j=x;j>=1;j--) D[j][y]=min(D[j][y],x);printf("%lld\n",ans);st[x][y]=1;}return 0; } /**/A - Namomo Subsequence
題意:
給你一個(gè)串sss,問你有多少個(gè)長(zhǎng)度為666且形如ABCDCDABCDCDABCDCD的子序列。
6≤∣s∣≤1e66\le |s|\le 1e66≤∣s∣≤1e6,字符集大小626262
思路:
考慮到字符集和長(zhǎng)度都很長(zhǎng),所以考慮62n62n62n的算法,62?62n62*62n62?62n的肯定過不去了。
直接維護(hù)肯定是不好弄的,可以發(fā)現(xiàn)能維護(hù)出來前兩個(gè)位置就不錯(cuò)了,所以我們考慮將其切割,分開來看。
將其分成ABABAB和CDCDCDCDCDCD兩個(gè)部分來看,枚舉CCC的位置,那么答案就是兩邊的方案數(shù)乘起來。
對(duì)于CDCDCDCDCDCD,我們比較容易維護(hù)出來,定義f[i][j][k]f[i][j][k]f[i][j][k]代表類型為iii的C=j,D=kC=j,D=kC=j,D=k的個(gè)數(shù),其中i=2i=2i=2代表ijijijijijij,i=1i=1i=1代表jijjijjij,i=0i=0i=0代表ijijij,那么轉(zhuǎn)移也比較容易,直接從上一個(gè)狀態(tài)切過來即可,注意每次f[2][j][k]f[2][j][k]f[2][j][k]都要清零。
由于很難將左邊的信息也記下來,記下來也需要62?6262*6262?62來遍歷,所以很不劃算。
考慮容斥,將左邊的所有方案(不包含相同字符個(gè)數(shù)相乘)直接于右邊相乘,考慮這樣多算了什么,顯然多算了A=C,A=D,B=D,B=CA=C,A=D,B=D,B=CA=C,A=D,B=D,B=C的情況,這個(gè)可以容斥來求。
復(fù)雜度O(62n)O(62n)O(62n)
//#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math") //#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native") //#pragma GCC optimize(2) #include<cstdio> #include<iostream> #include<string> #include<cstring> #include<map> #include<cmath> #include<cctype> #include<vector> #include<set> #include<queue> #include<algorithm> #include<sstream> #include<ctime> #include<cstdlib> #define X first #define Y second #define L (u<<1) #define R (u<<1|1) #define pb push_back #define mk make_pair #define Mid (tr[u].l+tr[u].r>>1) #define Len(u) (tr[u].r-tr[u].l+1) #define random(a,b) ((a)+rand()%((b)-(a)+1)) #define db puts("---") using namespace std;//void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); } //void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); } //void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }typedef long long LL; typedef unsigned long long ULL; typedef pair<int,int> PII;const int N=1000010,mod=998244353,INF=0x3f3f3f3f; const double eps=1e-6;int n; int a[N]; LL pre[N][64]; LL f[3][64][64],n2; char s[N];int get(char c) {if(c>='a'&&c<='z') return c-'a'+1;else if(c>='A'&&c<='Z') return c-'A'+27;else return c-'0'+53; }void add(LL &x,LL y) {x+=y; if(x>=mod) x-=mod; }void del(LL &x,LL y) {x-=y; if(x<0) x+=mod; }LL qmi(LL a,LL b) {LL ans=1;while(b) {if(b&1) ans=ans*a%mod;a=a*a%mod;b>>=1;}return ans%mod; }int main() { // ios::sync_with_stdio(false); // cin.tie(0);n2=qmi(2,mod-2);scanf("%s",s+1);n=strlen(s+1);for(int i=1;i<=n;i++) a[i]=get(s[i]);for(int i=1;i<=n;i++) {for(int j=1;j<=62;j++) {pre[i][j]=pre[i-1][j];}pre[i][a[i]]++;}LL ans=0;for(int i=n;i>=1;i--) {LL sum=0,all=i-1,i2=0;for(int j=1;j<=62;j++) add(i2,1ll*pre[i-1][j]*(all-pre[i-1][j])%mod);(i2*=n2)%=mod;for(int j=1;j<=62;j++) {if(a[i]==j) continue;add(f[2][a[i]][j],f[1][a[i]][j]);add(f[0][a[i]][j],1ll*pre[n][j]-pre[i][j]);add(f[1][j][a[i]],f[0][j][a[i]]);LL mul=((i2-pre[i-1][j]*(all-pre[i-1][j])%mod)%mod-pre[i-1][a[i]]*(all-pre[i-1][a[i]])%mod)%mod+pre[i-1][j]*pre[i-1][a[i]]%mod;mul%=mod; mul+=mod; mul%=mod;add(ans,f[2][a[i]][j]*mul%mod);f[2][a[i]][j]=0;}}printf("%lld\n",ans);return 0; } /**/D - City Brain
題意:
給你一個(gè)nnn個(gè)點(diǎn)mmm條邊的無向圖,邊權(quán)初始為111,你可以對(duì)邊進(jìn)行kkk此操作,每次選擇任意邊,假設(shè)某條邊操作了xxx次,那么他的權(quán)值就變成了1x\frac{1}{x}x1?,給你兩對(duì)起點(diǎn)終點(diǎn),問對(duì)邊操作完之后,從兩對(duì)起點(diǎn)到相應(yīng)終點(diǎn)的路徑和最短是多長(zhǎng)。
n,m≤5000,0≤k≤1e9n,m\le 5000,0\le k\le 1e9n,m≤5000,0≤k≤1e9
思路:
考慮如果兩個(gè)路徑有重疊,那么肯定是與在兩條路各個(gè)路徑上走不同的,所以考慮能否將其拿出來,單獨(dú)考慮。
考慮如果兩條路徑有兩部分是重疊的,那么肯定不優(yōu)于兩個(gè)人都從第一個(gè)重疊開始走同一路徑到下一個(gè)重疊優(yōu),這樣重疊就變成一段連續(xù)的區(qū)間,所以結(jié)論就是兩條路徑如果有重疊,那么一定是連續(xù)的一段。
考慮枚舉重疊部分的長(zhǎng)度,假設(shè)為lll,那么預(yù)處理一下重疊部分為lll的時(shí)候其他路徑的最短和len[l]len[l]len[l],這個(gè)n2n^2n2可以處理出來,我們發(fā)現(xiàn)我們不好確認(rèn)分給重疊部分的次數(shù)多少,但是這時(shí)一個(gè)凹函數(shù),所以我們?nèi)纸o重疊部分的操作次數(shù),讓后checkcheckcheck一下,問題又變成了給長(zhǎng)度為lenlenlen的路徑分配xxx次操作的最小代價(jià),這個(gè)還是比較容易考慮的,首先就是均分次數(shù),多余的次數(shù)也是均分,算一下就好,注意不要除000。
還有細(xì)節(jié)就是n2n^2n2處理lenlenlen的時(shí)候,枚舉的公共路徑的端點(diǎn)i,ji,ji,j的時(shí)候,要分s1?>i,j?>t1s1->i,j->t1s1?>i,j?>t1還有s1?>j,i?>t1s1->j,i->t1s1?>j,i?>t1兩種情況,對(duì)于s2,t2s2,t2s2,t2同理。
//#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math") //#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native") //#pragma GCC optimize(2) #include<cstdio> #include<iostream> #include<string> #include<cstring> #include<map> #include<cmath> #include<cctype> #include<vector> #include<set> #include<queue> #include<algorithm> #include<sstream> #include<ctime> #include<cstdlib> #define X first #define Y second #define L (u<<1) #define R (u<<1|1) #define pb push_back #define mk make_pair #define Mid (tr[u].l+tr[u].r>>1) #define Len(u) (tr[u].r-tr[u].l+1) #define random(a,b) ((a)+rand()%((b)-(a)+1)) #define db puts("---") using namespace std;//void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); } //void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); } //void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }typedef long long LL; typedef unsigned long long ULL; typedef pair<int,int> PII;const int N=5010,mod=998244353,INF=0x3f3f3f3f; const double eps=1e-6;int n,m,k; int s1,s2,t1,t2; int dis[N][N]; vector<int>v[N]; int len[N];//計(jì)算路徑長(zhǎng)度為x,能分配p個(gè)的時(shí)候最小值 double get(int p,int x) {if(x==0) return 0;int cnt=p/x,rest=p%x;return 1.0/(cnt+1)*(x-rest)+1.0/(cnt+2)*rest; }//返回分配給共同路徑mid個(gè),非共同路徑k-mid個(gè)的答案 double check(int mid,int x) {int c1=k-mid,c2=mid;return get(c1,len[x])+get(c2,x)*2; }int main() { // ios::sync_with_stdio(false); // cin.tie(0);scanf("%d%d%d",&n,&m,&k);for(int i=1;i<=m;i++) {int a,b; scanf("%d%d",&a,&b);v[a].pb(b); v[b].pb(a);}scanf("%d%d%d%d",&s1,&t1,&s2,&t2);for(int i=1;i<=n;i++) {queue<int>q; q.push(i);for(int j=1;j<=n;j++) dis[i][j]=INF;dis[i][i]=0;while(q.size()) {int u=q.front(); q.pop();for(auto x:v[u]) {if(dis[i][x]>dis[i][u]+1) {dis[i][x]=dis[i][u]+1;q.push(x);}}}}memset(len,0x3f,sizeof(len));len[0]=dis[s1][t1]+dis[s2][t2];for(int i=1;i<=n;i++) {for(int j=1;j<=n;j++) {int l=dis[i][j];if(l==INF) continue;if(!(dis[s1][i]==INF||dis[j][t1]==INF||dis[s2][i]==INF||dis[j][t2]==INF))len[l]=min(len[l],dis[s1][i]+dis[j][t1]+dis[s2][i]+dis[j][t2]);if(!(dis[s1][j]==INF||dis[i][t1]==INF||dis[s2][i]==INF||dis[j][t2]==INF))len[l]=min(len[l],dis[s1][j]+dis[i][t1]+dis[s2][i]+dis[j][t2]);if(!(dis[s1][i]==INF||dis[j][t1]==INF||dis[s2][j]==INF||dis[i][t2]==INF))len[l]=min(len[l],dis[s1][i]+dis[j][t1]+dis[s2][j]+dis[i][t2]);if(!(dis[s1][j]==INF||dis[i][t1]==INF||dis[s2][j]==INF||dis[i][t2]==INF))len[l]=min(len[l],dis[s1][j]+dis[i][t1]+dis[s2][j]+dis[i][t2]);}}double ans=1e13;for(int x=0;x<=n;x++) {if(len[x]==INF) continue;int l=0,r=k;while(l<=r) {int mid1=l+(r-l)/3,mid2=r-(r-l)/3;if(check(mid1,x)<check(mid2,x)) r=mid2-1;else l=mid1+1;}ans=min(ans,check(r,x));}printf("%.13f\n",ans);return 0; } /* 10 9 19 5 2 4 1 2 1 6 5 10 8 8 1 9 3 7 6 1 3 7 7 6 4 */總結(jié)
以上是生活随笔為你收集整理的2020EC-final的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电脑截图如何全部拼接在一起如何拼图电脑
- 下一篇: xp系统如何用路由器连接wifi怎样连接