Tenka1 Programmer Contest 2019
A.一定是前半段白后半段黑,枚举分界点预处理前后缀和。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 6 typedef long long ll; 7 using namespace std; 8 9 const int N=200010; 10 char s[N]; 11 int n,ans,pre[N],suf[N]; 12 13 int main(){ 14 freopen("a.in","r",stdin); 15 freopen("a.out","w",stdout); 16 scanf("%d%s",&n,s+1); ans=n+1; 17 rep(i,1,n) pre[i]=pre[i-1]+(s[i]=='#'); 18 for (int i=n; i; i--) suf[i]=suf[i+1]+(s[i]=='.'); 19 rep(i,0,n) ans=min(ans,pre[i]+suf[i+1]); 20 printf("%d\n",ans); 21 return 0; 22 }
B.总数-存在某个集合超过总和一半的方案数,先默认这个大集合是R最后再乘3。
f[i][j]表示前i个数中R中数之和为j,不在R中的数随意放入G和B的方案数。发现这样可能会多考虑空集,于是再令g[i][j]表示前i个数中R中数和为j,不在R中的数全部放入G的方案数,做个类似的DP即可。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 6 typedef long long ll; 7 using namespace std; 8 9 const int N=310,mod=998244353; 10 int n,ans,sm,a[N],f[N*N],g[N*N]; 11 12 int ksm(int a,int b){ 13 int res=1; 14 for (; b; a=1ll*a*a%mod,b>>=1) 15 if (b & 1) res=1ll*res*a%mod; 16 return res; 17 } 18 19 int main(){ 20 freopen("b.in","r",stdin); 21 freopen("b.out","w",stdout); 22 scanf("%d",&n); ans=(ksm(3,n)-3ll*ksm(2,n)+3+3ll*mod)%mod; 23 rep(i,1,n) scanf("%d",&a[i]),sm+=a[i]; 24 f[0]=g[0]=1; 25 rep(i,1,n) for (int j=sm; ~j; j--){ 26 f[j]=(f[j]*2ll+(j>=a[i]?f[j-a[i]]:0))%mod; 27 g[j]=(g[j]+(j>=a[i]?g[j-a[i]]:0))%mod; 28 } 29 rep(i,(sm+1)/2,sm-1) ans=(ans-3ll*(f[i]-2ll*g[i])+3ll*mod)%mod; 30 printf("%d\n",ans); 31 return 0; 32 }
C.结论:p能成为答案,当且仅当:p是所有系数gcd的质因子,或(x^p-x)能整除原多项式。
第一种情况由裴蜀定理知显然。第二种情况我是这样理解的:若两个多项式次数相同且所有根都相同,那么它们就是同一个多项式,在模意义下或许同样如此。那么由于1~p-1全部为原多项式的根,也就是x(x-1)(x-2)...(x-p+1)能整除原式。而这个式子和(x^p-x)在模p意义下是相等的,于是直接判断(x^p-x)能否整除原式即可。
下面考虑如何判断(x^n-1)是否整除一个多项式,发现只要判断“所有%n同余的次数项的系数之和是否全为0”即可。总复杂度O(n^2)。
1 #include<set> 2 #include<cstdio> 3 #include<algorithm> 4 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 5 typedef long long ll; 6 using namespace std; 7 8 const int N=200010; 9 int n,m,a[N],h[N]; 10 set<int>ans; 11 12 void chk(int p){ 13 rep(i,0,p-2) h[i]=0; 14 rep(i,0,n) h[i%(p-1)]=(h[i%(p-1)]+a[i])%p; 15 rep(i,0,p-2) if (h[i]) return; 16 ans.insert(p); 17 } 18 19 int main(){ 20 freopen("c.in","r",stdin); 21 freopen("c.out","w",stdout); 22 scanf("%d",&n); 23 for (int i=n; ~i; i--) scanf("%d",&a[i]),m=__gcd(m,abs(a[i])); 24 for (int i=2; i*i<=m; i++) if (m%i==0){ 25 ans.insert(i); 26 while (m%i==0) m/=i; 27 } 28 if (m!=1) ans.insert(m); 29 rep(i,2,n) if (a[0]%i==0){ 30 bool flag=1; 31 for (int j=2; j*j<=i; j++) if (i%j==0){ flag=0; break; } 32 if (flag) chk(i); 33 } 34 for (set<int>::iterator it=ans.begin(); it!=ans.end(); it++) printf("%d\n",*it); 35 return 0; 36 }