1. 程式人生 > 其它 >7.11洛谷多校5補

7.11洛谷多校5補

A

長度為n的包含小寫字母的字串,有m種變換關係,可以把某個字母花費一定代價變成另一個字母,某個字串被變為迴文串的代價稱為最小回文代價,對所有子串,求最小回文代價的和。

n<=10^5

題解:

一開始我看錯題了,以為這個代價是隻要首尾相同就行了,打完之後發現錯了。

但實際上沒什麼區別,改了一點點又過了。

首先用floyd求兩兩字母變成相同的所需的最小代價f[x][y]

考慮兩個位置i<j,這兩個位置產生的代價是min(i,n-j+1)*f[s[x]][s[y]]

這個代價可以用字首和來算。

程式碼:

 1 #include<bits/stdc++.h>
 2 using namespace
std; 3 int a[100010],f[30][30],aa[30][30],c[30],ss[100010][30]; 4 long long st[100010][30]; 5 int main() 6 { 7 int n,m; 8 scanf("%d%d",&n,&m); 9 char s[1000010]; 10 scanf("%s",s+1); 11 for (int i=1;i<=n;i++) a[i]=s[i]-'a',c[a[i]]++; 12 getchar(); 13 for (int i=0;i<=25;i++) for
(int j=0;j<=25;j++) f[i][j]=f[j][i]=30*20000; 14 for (int i=0;i<=25;i++) f[i][i]=0; 15 for (int i=1;i<=m;i++) 16 { 17 char x,y; 18 int z; 19 scanf("%c %c %d",&x,&y,&z); 20 getchar(); 21 f[x-'a'][y-'a']=z; 22 } 23 for (int k=0;k<=25
;k++) for (int i=0;i<=25;i++) for (int j=0;j<=25;j++) if (i!=j&&i!=k&&j!=k) f[i][j]=min(f[i][j],f[i][k]+f[k][j]); 24 for (int i=0;i<=25;i++) for (int j=0;j<=25;j++) 25 { 26 if (i==j) continue; 27 aa[i][j]=min(f[i][j],f[j][i]); 28 for (int k=0;k<=25;k++) if (i!=k&&j!=k) aa[i][j]=min(aa[i][j],f[i][k]+f[j][k]); 29 } 30 long long ans=0; 31 for (int i=1;i<=n;i++) for (int j=0;j<=25;j++) 32 { 33 ss[i][j]=ss[i-1][j]; 34 st[i][j]=st[i-1][j]; 35 if (j==a[i]) ss[i][j]++,st[i][j]+=i; 36 } 37 for (int i=1;i<=n;i++) 38 { 39 for (int j=0;j<=25;j++) 40 { 41 if (a[i]==j) continue; 42 int mn=30*20000; 43 mn=min(aa[j][a[i]],min(aa[a[i]][j],mn)); 44 if (mn==30*20000) continue; 45 int tt=n-i; 46 if (i>=tt+2) ans=ans+1ll*st[tt+1][j]*mn+1ll*(ss[i-1][j]-ss[tt+1][j])*(tt+1)*mn; 47 else ans=ans+1ll*st[i][j]*mn; 48 } 49 } 50 printf("%lld\n",ans); 51 }

B

兩個01串,一個操作序列,這個操作序列表示,第i天會把第a[i]位取反,每天有一次額外的機會修改串的某一位,問最早哪一天可以使得兩個串相同。

<=10^5

題解:

二分答案,直接模擬判斷即可。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int a[200020],b[200020],c[200020];
 4 int main()
 5 {
 6     int n,t;
 7     scanf("%d%d",&n,&t);
 8     char s1[200010],s2[200010];
 9     scanf("%s",s1+1);
10     scanf("%s",s2+1);
11     for (int i=1;i<=t;i++) scanf("%d",&a[i]);
12     int l=0,r=t,ans=-1;
13     while (l<=r)
14     {
15         int mid=l+r>>1;
16         for (int i=1;i<=n;i++) b[i]=s1[i]-'0',c[i]=s2[i]-'0';
17         for (int i=1;i<=mid;i++) b[n-a[i]]=1-b[n-a[i]];
18         int tmp=0;
19         for (int i=1;i<=n;i++) if (b[i]!=c[i]) tmp++;
20         if (tmp<=mid) 
21         {
22             ans=mid;
23             r=mid-1;
24         }else l=mid+1;
25     }
26     if (ans!=-1) printf("%d\n",ans);else printf("icu\n");
27 }

E

ABC三種磚塊,A只有一塊,BC無使用限制。

給定一個目標圖形,磚塊之間不能重疊,問在使用了A的情況下不同的方案數及方案。

兩個方案不同,當且僅當A放置的位置不同

n,m<=500

題解:

喵喵喵,太喵了

觀察可以發現,A所在的對角線,一定有奇數個格子需要被覆蓋。

這樣就可以把A所在區域縮小到O(n+m)級別。

剩下就是暴力判斷了

不得不說,喵得離譜