ATPの水题大赛
声明:不是我觉得这题水,这就是本场模拟赛的名称。
T1:求所有的$n$位数中有几个数满足:每一位要么是$A$要么是$B$,并且这个$n$位数的每一位加起来是$A$或$B$的倍数。
$n<=100000,0<A,B<=9$且$A$与$B$不相等
因为昨天刚讲了数位$dp$,理所当然的就往那方面去想了.其实用组合数学也可以做,而且还比较简短.
用$f[i][j][k]$表示目前填到第$i$位,对$a$取模余数为$j$,对$b$取模余数为$k$的方案数.滚动数组,空间可以压得非常小.
1 # include <cstdio> 2 # include <iostream> 3 # include <cstring> 4 # include <string> 5 # define R register int 6 # define mod 1000000007 7 8 using namespace std; 9 10 const int maxn=100005; 11 int dp[3][10][10]; 12 int a,b,n,ans,no,nex; 13 14 inline int ad (int a,int b) { a=a+b; if(a>=mod) a-=mod; return a; } 15 16 int solve () 17 { 18 dp[0][0][0]=1; 19 for (R i=0;i<n;++i) 20 { 21 no=i&1; 22 nex=no^1; 23 memset(dp[nex],0,sizeof(dp[nex])); 24 for (R m1=0;m1<a;++m1) 25 for (R m2=0;m2<b;++m2) 26 { 27 if(!dp[no][m1][m2]) continue; 28 dp[nex][m1][(m2+a)%b]=ad(dp[no][m1][m2],dp[nex][m1][(m2+a)%b]); 29 dp[nex][(m1+b)%a][m2]=ad(dp[no][m1][m2],dp[nex][(m1+b)%a][m2]); 30 } 31 } 32 int ans=0; 33 for (R m1=0;m1<a;++m1) 34 for (R m2=0;m2<b;++m2) 35 if(m1==0||m2==0) ans=ad(ans,dp[n&1][m1][m2]); 36 return ans; 37 } 38 39 int main() 40 { 41 scanf("%d%d%d",&n,&a,&b); 42 printf("%d",solve()); 43 return 0; 44 }
T2:求逆序对数量*360。没了。
1 # include <cstdio> 2 # include <iostream> 3 # include <cstring> 4 # include <string> 5 # include <algorithm> 6 # define R register int 7 # define lowbit(i) (i&(-i)) 8 # define mod 1000000007 9 10 using namespace std; 11 12 const int maxn=500005; 13 struct nod 14 { 15 int key,val; 16 }a[maxn]; 17 int n,v[maxn]; 18 int t[maxn],ans,cnt; 19 20 bool cmp (nod a,nod b) { return a.val<b.val; } 21 22 void add (int pos,int val) 23 { 24 for (R i=pos;i<=cnt;i+=lowbit(i)) t[i]+=val; 25 } 26 27 int ask (int pos) 28 { 29 int ans=0; 30 for (R i=pos;i;i-=lowbit(i)) ans+=t[i]; 31 return ans; 32 } 33 34 int main() 35 { 36 scanf("%d",&n); 37 for (R i=1;i<=n;++i) 38 scanf("%d",&a[i].val),a[i].key=i; 39 sort(a+1,a+1+n,cmp); 40 a[0].val=a[1].val+1; 41 for (R i=1;i<=n;++i) 42 { 43 if(a[i].val!=a[i-1].val) ++cnt; 44 v[ a[i].key ]=cnt; 45 } 46 for (R i=1;i<=n;++i) 47 { 48 ans+=ask(cnt)-ask(v[i]); 49 if(ans>=mod) ans-=mod; 50 add(v[i],1); 51 } 52 ans=(long long)ans*360%mod; 53 printf("%d",ans); 54 return 0; 55 }
T3:给定一棵正边权的树,求离每个点最远的点有多远;
有一个定理:离每个点最远的点必然是直径端点上的一点,不过...我不是这么做的。
以任意点为端点的最长路要么在它的子树里面,要么是从父亲走过来的,经典的$up and down$题目.注意,父亲的最长路有可能本来就是从自己这里走过去的,再用父亲来更新就会走重复的路径了.那怎么办呢?再记录一条次长路径即可,细节什么的...自己想吧。
1 # include <cstdio> 2 # include <iostream> 3 # include <cstring> 4 # include <string> 5 # define R register int 6 7 using namespace std; 8 9 const int maxn=1000006; 10 int n,h,x,y,co,firs[maxn],dep[maxn],m1[maxn],m2[maxn]; 11 struct edge 12 { 13 int too,nex,co; 14 }g[maxn<<1]; 15 16 int read() 17 { 18 int x=0,f=1; 19 char c=getchar(); 20 while (!isdigit(c)) { if(c=='-') f=-f; c=getchar(); } 21 while (isdigit(c)) { x=(x<<3)+(x<<1)+(c^48); c=getchar(); } 22 return x*f; 23 } 24 25 void add (int x,int y,int co) 26 { 27 g[++h].too=y; 28 g[h].co=co; 29 g[h].nex=firs[x]; 30 firs[x]=h; 31 } 32 33 void upp (int x) 34 { 35 int j,len; 36 for (R i=firs[x];i;i=g[i].nex) 37 { 38 j=g[i].too; 39 if(dep[j]) continue; 40 dep[j]=dep[x]+1; 41 upp(j); 42 len=m1[j]+g[i].co; 43 if(len>m1[x]) m2[x]=m1[x],m1[x]=len; 44 else if(len==m1[x]) m2[x]=len; 45 else m2[x]=max(m2[x],len); 46 } 47 } 48 49 void dowwn (int x) 50 { 51 int j,len; 52 for (R i=firs[x];i;i=g[i].nex) 53 { 54 j=g[i].too; 55 if(dep[j]<dep[x]) continue; 56 len=m1[x]; 57 if(len==m1[j]+g[i].co) len=m2[x]; 58 len+=g[i].co; 59 if(len>m1[j]) m1[j]=len; 60 else if(len==m1[j]) m2[j]=len; 61 else m2[j]=max(m2[j],len); 62 dowwn(j); 63 } 64 } 65 66 int main() 67 { 68 n=read(); 69 for (R i=1;i<n;++i) 70 { 71 x=read(),y=read(),co=read(); 72 add(x,y,co); 73 add(y,x,co); 74 } 75 dep[1]=1; 76 upp(1); 77 dowwn(1); 78 for (R i=1;i<n;++i) 79 printf("%d ",m1[i]); 80 printf("%d",m1[n]); 81 return 0; 82 }
T4:带修改动态逆序对。
$n$为序列长度,$m$为修改次数.
这题好啊,不用写代码,只需要写一个做法的$txt$,学姐看做法给分qwq.正好是只会说不会写.
这个做法竟然被给了满分QAQ
---shzr