Link:
A:
判断如果一个方向有,其相反方向有没有即可
#include <bits/stdc++.h> using namespace std; char s[1005]; map<char,bool> mp; int main() { scanf("%s",s); for(int i=0;i<strlen(s);i++) mp[s[i]]=true; if(mp['S']==mp['N']&&mp['E']==mp['W']) puts("Yes"); else puts("No"); return 0; }
B:
贪心最大化利用即可
#include <bits/stdc++.h> using namespace std; int n,dat[100005]; long long res=0; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&dat[i]); for(int i=1;i<=n-1;i++) { res+=dat[i]/2;dat[i]%=2; if(dat[i+1]>dat[i]) dat[i+1]-=dat[i],res+=dat[i]; } res+=dat[n]/2; printf("%lld",res); return 0; }
C:
可以将两个操作转换为:
1、交换两个相邻的数
2、交换两个中间相间一个的数
由于只要求操作1的最小数,可以发现调整好所有数的序号的奇偶性就能用操作2完成任务
因此求出原序号为奇数,排序后序号为偶数的数的个数即可(原偶现奇的个数与其相同)
#include <bits/stdc++.h> using namespace std; int n,dat[100005],id[100005]; bool cmp(int a,int b) {return dat[a]<dat[b];} int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&dat[i]),id[i]=i; sort(id+1,id+n+1,cmp); int res=0; for(int i=1;i<=n;i++) if((id[i]&1)&&!(i&1)) res++; printf("%d",res); return 0; }
D:
思路类似于 [Codeforces#480 D] ,只不过将平方改成了立方
要判断两个数的积为立方,可以将每个数的各个质因数次幂$mod 3$化简后再判断
于是我们求出每个数化简后的结果,统计出现次数,同时求出化简后的数的补数
最后在一个数及其补数中选择个数更多的那一组即可(特判:如果化简后为1只能算一个)
实现的难点在质因数分解……
由于$nle 10^{10}$,肯定不能求出$n$以内的所有质数
于是要先将$10^{frac{10}{3}}$内的质因数分解掉,保证剩下的质因数的次幂不会超过2次
实际上,剩下的数只有3种情况,分类讨论就好了:
1、$p^2$ 2、$p$ 3、$p*q$ ($p,q$为质数)
这样就能在$O(1)$的时间内计算大于$10^{frac{10}{3}}$的质因数的化简结果及其补数了
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int MAXN=1e5+10; int n,pri[3005],vis[3005],tot,res=0; ll x[MAXN],y[MAXN],t; map<ll,int> mp,avl; ll cube(int a){return 1ll*a*a*a;} ll sqr(int a){return 1ll*a*a;} int main() { for(int i=2;i<=3000;i++) { if(!vis[i]) pri[++tot]=i; for(int j=1;j<=tot&&i*pri[j]<=3000;j++) { vis[i*pri[j]]=1; if(i%pri[j]==0) break; } } scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%lld",&t);x[i]=y[i]=1; for(int j=1;cube(pri[j])<=t;j++) { int cnt=0; while(t%pri[j]==0) t/=pri[j],cnt++; if(cnt%3==1) x[i]*=pri[j],y[i]*=sqr(pri[j]); else if(cnt%3==2) x[i]*=sqr(pri[j]),y[i]*=pri[j]; } x[i]*=t;mp[x[i]]++; y[i]*=sqr(sqrt(t))==t?sqrt(t):sqr(t); } for(int i=1;i<=n;i++) if(!avl[x[i]]) { avl[x[i]]=avl[y[i]]=1; if(x[i]==1) res++; else res+=max(mp[x[i]],mp[y[i]]); } printf("%d",res); return 0; }
如果操作为除法/取模,且要枚举$n$个除数/模数时,
学会较小数暴力,较大数分类讨论的方式(如 [ARC060 D])
E:
首先可以将$dat$序列改为单调递增的,其他项明显是多余的
通过观察发现每一项可以由之前的项重复、组合而成(可能留有小于$len[1]$的后缀)
于是我们令$cnt[i]$为第$i$项被重复的总次数,对于从后往前每一个$i$:
每次二分找到最大的小于$dat[i]$的$dat[j]$,那么第$j$项可以多重复$dat[i]/dat[j]*cnt[i]$次
接下来将$dat[i]$mod$dat[j]$,寻找下一个重复项
由于一个数$mod$比自己小的数明显最多进行$log(n)$次,因此复杂度为$O(n*log(n))$
由于每项在整块整块分解后仍可能有小于$len[1]$的后缀,需要另外统计
为了保证时间复杂度,且由于该后缀一定连续,因此差分统计就好了
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int MAXN=1e5+10; int n,q,tot; ll res[MAXN],dat[MAXN],cnt[MAXN]; int Query(ll x,int r) { int ret=-1,l=0; while(l<=r) { int mid=(l+r)>>1; if(dat[mid]<=x) ret=mid,l=mid+1; else r=mid-1; } return ret; } int main() { scanf("%d%d",&n,&q); for(int i=1;i<=q;i++) scanf("%lld",&dat[i]); dat[0]=n;//如果最小值大于n要添加n for(int i=1;i<=q;i++) { while(tot>=0&&dat[i]<dat[tot]) tot--; dat[++tot]=dat[i]; } cnt[tot]=1; for(int i=tot;i>=0;i--) { ll k=dat[i],pos=Query(k,i-1); while(pos>=0) { cnt[pos]+=(k/dat[pos])*cnt[i]; k=k%dat[pos];pos=Query(k,pos-1); } res[1]+=cnt[i];res[k+1]-=cnt[i]; } for(int i=1;i<=n;i++) res[i]+=res[i-1],printf("%lld ",res[i]); return 0; }
F:
%%%LCA的题解:https://loj.ac/article/189
一眼看上去完全不可做的题(好像对我而言所有题都这样)
但先进行大的分类后其实会发现明朗很多
令矩阵中有色点数为$cnt$,上下/左右相邻的有色点对数分别为$pv,ph$
令原矩阵上下/左右拼接后能连通的列数/行数分别为$sv,sh$
1、如果$sv,sh$都大于零,明显全部连通
2、如果$sv,sh$都为零,明显答案为$cnt^{k-1}$
3、如果$sv,sh$中恰有一个大于零,需要递推:
将最终矩阵中每一个初始矩阵视为一个点,两点相连通则视为有一条边
由于最终状态不可能有环,求连通块的个数,其实就是求点数与边数的差
根据上面求出的量,可以写出如下的递推式:
$V_k=V_{k-1}*cnt$
$E_k=E_{k-1}*cnt+pv(h)*sv(h)$
对于这样的式子矩乘优化就好了
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int MOD=1e9+7,MAXN=1005; struct matrix { ll p[5][5]; matrix(){memset(p,0,sizeof(p));} void init(){p[0][0]=p[1][1]=1;} friend matrix operator * (const matrix &a,const matrix &b) { matrix ret; for(int i=0;i<2;i++) for(int j=0;j<2;j++) for(int k=0;k<2;k++) (ret.p[i][j]+=a.p[i][k]*b.p[k][j]%MOD)%=MOD; return ret; } friend matrix quick_pow(matrix a,ll b) { matrix ret;ret.init(); for(;b;b>>=1,a=a*a) if(b&1) ret=ret*a; return ret; } }; char s[MAXN][MAXN]; ll k; int n,m,cnt,pv,ph,sv,sh; ll quick_pow(ll a,ll b) { ll ret=1; for(;b;b>>=1,a=a*a%MOD) if(b&1) ret=ret*a%MOD; return ret; } int main() { scanf("%d%d%lld",&n,&m,&k); if(k<=1) return puts("1"),0; for(int i=1;i<=n;i++) scanf("%s",s[i]+1); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(s[i][j]=='#') { cnt++; pv+=(s[i][j]==s[i+1][j]); ph+=(s[i][j]==s[i][j+1]); } for(int i=1;i<=m;i++) sv+=(s[1][i]=='#'&&s[n][i]=='#'); for(int i=1;i<=n;i++) sh+=(s[i][1]=='#'&&s[i][m]=='#'); if(sv&&sh) return puts("1"),0; else if(!sv&&!sh) return printf("%lld",quick_pow(cnt,k-1)),0; else { matrix t;t.p[0][0]=cnt;t.p[1][0]=(sv?pv:0)+(sh?ph:0);t.p[1][1]=sv+sh; t=quick_pow(t,k-1);printf("%lld",(t.p[0][0]-t.p[1][0]+MOD)%MOD); } return 0; }