ICPC小米网络赛第二场
A
对于第一个2,统计即可。
对于第一个0,统计的同时还要看会不会超过第一个2的数量,因为超过了,我们也没有前面的2与之进行匹配。
对于第二个2,统计的同时还要看会不会超过第一个0的数量,同时,我们还要注意,我们不能超过第一个2的数量的一半,因为我们要使得匹配数尽量大,总共2的数量尽量要对半分。
对于第二个0,同理。
#include <bits/stdc++.h> #define debug freopen("r.txt","r",stdin) #define mp make_pair #define ri register int #define pb push_back using namespace std; typedef long long ll; typedef double lf; typedef pair<ll, ll> pii; const int maxn = 1e6+10; const ll INF = 1e18; const int mod = 1e9+7; const double eps=1e-6; const double PI=acos(-1.0); inline ll read(){ll s=0,w=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar(); return s*w;} ll qpow(ll p,ll q){return (q&1?p:1)*(q?qpow(p*p%mod,q/2):1)%mod;} int n,i,l2,l0,r2,r0; char s[maxn]; int main() { while (~scanf("%d",&n)) { scanf("%s",s+1); l2=l0=r2=r0=0; for (i=1;i<=n;i++) { int x=(s[i]-'0'); l2+=(x==2); l0+=(x==0 && l0<l2); r2+=(x==2 && r2<(l2>>1) && r2<l0); r0+=(x==0 && r0<(l0>>1) && r0<r2); } cout<<r0<<endl; } return 0; }
D
水题?我并不这么认为……,也可能是我线代知识掌握的不牢固的原因。
G
对于每次操作,可以近似看为,一个环,把它从某个位置断开,然后展开的操作。顺序、逆序,一共2n遍,同时判重使用hash。
#include <bits/stdc++.h> #define debug freopen("r.txt","r",stdin) #define mp make_pair #define ri register int #define pb push_back using namespace std; typedef long long ll; typedef long long ull; typedef double lf; typedef pair<ll, ll> pii; const int maxn = 1e6+10; const ll INF = 1e18; const int mod = 1e9+7; const int hash_num = 131; const double eps=1e-6; const double PI=acos(-1.0); inline ll read(){ll s=0,w=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar(); return s*w;} ll qpow(ll p,ll q){return (q&1?p:1)*(q?qpow(p*p%mod,q/2):1)%mod;} map<ull,int>mapp; ull hash1[maxn], base[maxn]; int n,i,a[maxn],num; ull get_hash(int l,int r) { return hash1[r]-hash1[l-1]*base[r-l+1]; } void _hash() { for (int i=1;i<=2*n;i++) hash1[i]=hash1[i-1]*hash_num+(a[i]); } void init() { base[0]=1; for (int i=1;i<=maxn;i++) base[i]=base[i-1]*hash_num; } int main() { init(); while (~scanf("%d",&n)) { mapp.clear(); for (i=1;i<=n;i++) a[i]=read(),a[i+n]=a[i]; _hash(); ull sum=0; num=0; for (i=1;i<=n;i++) { sum=get_hash(i,i+n-1); if (!mapp[sum]) num++; mapp[sum]=1; } reverse(a+1,a+1+2*n); _hash(); for (i=1;i<=n;i++) { sum=get_hash(i,i+n-1); if (!mapp[sum]) num++; mapp[sum]=1; } cout<<num<<endl; } return 0; }
H
这题的正解我不会……,正解是需要分治的那种,而不是以性价比排序的那种,虽然两种都能过,但是第二种会被hack。分治那种用到了一个我听都没听过的算法,而我也没学会……
I
首先很容易想到的和最长公共子序列有关,应该算是拓展题。
假设串a匹配到第 i 个位置,串b匹配到第 j 个位置,对于串a的下一位字母 i+1,如果它字典序小于串b的下一位字母 j+1,那么我们可以把串b后面的字母都能加进来,统计一次答案了。
而第二种统计答案的方法是,找到两者的最长公共子序列,再把串b后面的字母加进来,统计答案。
#include <bits/stdc++.h> #define debug freopen("r.txt","r",stdin) #define mp make_pair #define ri register int #define pb push_back using namespace std; typedef long long ll; typedef double lf; typedef pair<ll, ll> pii; const int maxn = 2e3+10; const ll INF = 1e18; const int mod = 1e9+7; const double eps=1e-6; const double PI=acos(-1.0); inline ll read(){ll s=0,w=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar(); return s*w;} ll qpow(ll p,ll q){return (q&1?p:1)*(q?qpow(p*p%mod,q/2):1)%mod;} char s1[maxn],s2[maxn]; int len1,len2,ans,i,j,dp[maxn][maxn]; int main() { while (~scanf("%s%s",s1+1,s2+1)) { len1=strlen(s1+1); len2=strlen(s2+1); for (i=0;i<=len1;i++) for (j=0;j<=len2;j++) dp[i][j]=0; ans=0; for (i=0;i<=len1;i++) for (j=0;j<=len2;j++) { if (i && j) { dp[i][j]=max(dp[i][j-1],dp[i-1][j]); if (s1[i]==s2[j]) dp[i][j]=dp[i-1][j-1]+1; else if (s1[i]<s2[j]) { ans=max(ans,dp[i-1][j-1]*2+len1-i+1+len2-j+1); } } ans=max(ans,dp[i][j]*2+(len2-j)); } cout<<ans<<endl; } return 0; }