A题:给你一串只有0和1的字符串,让你通过使一个区间异或后所得的字符串中1的个数最大。
小结:题目以来没想太多,以为是找最长有多少个0,直接交了一发WA,最后看了下数据,暴力秒过。
代码:
#include<iostream> using namespace std; int sum[105]; int a[105]; int main() { int n; cin>>n; sum[0]=0; for(int i=1;i<=n;i++) { cin>>a[i]; sum[i]=sum[i-1]+a[i]; } int max=-1; int ans1,ans2; for(int i=1;i<=n;i++) { for(int j=i;j<=n;j++) { ans1=sum[j]-sum[i-1]; ans2=j-i+1-ans1; ans2=ans2+sum[i-1]+sum[n]-sum[j]; if(ans2>max) max=ans2; } } cout<<max<<endl; return 0; }B题:让你构造一串数,使得后面一个不能别前面的任意一个数整除。
小结:这题以来没想过直接打素数表,数的长度为10^5,而数的范围是10^7,以为10^7中不可能有10^5个素数,后来测试了下,第10^5个素数才1200000左右。
代码:
#include<iostream> using namespace std; int a[1500000]; int main() { int n; a[1]=0; for(int i=2;i<=1500000;i++) { if(a[i]==0) { for(int j=i+i;j<=1500000;j+=i) a[j]=1; } } cin>>n; int count=0; for(int i=2;i<=10000000;i++) { if(a[i]==0) { cout<<a[i]; count++; if(count!=n) { cout<<' '; } else { cout<<endl; break; } } } return 0; }C题:让你找公式,然后用快速幂取余,还得使用费马小定理求逆元。
费马小定理:(a,p)=1,则a^(p-1)=1modp;
快速幂:
//a^nmodb long long POW(long long a,long long n,long long b) { long long ret=1; while(n) { if(n&1) { ret=(ret*a)%b; } n/=2; a=(a*a)&b; } return ret; }这里还用到了预处理,2^n
代码:
#include<iostream> #include<cstring> #include<cmath> #define N 1000000007 #define ll long long using namespace std; char s[100005]; int p[100005]; void init() { p[0]=1; for(int i=1;i<=100005;i++)//2^n { p[i]=(p[i-1]*2)%N; } } long long f(long long a,long long n,long long b) { long long t=a; long long ans=1; while(n) { if(n&1) { ans=(ans*t)%b; } n>>=1; t=(t*t)%b; } return ans; } int main() { long long k; cin>>s; cin>>k; long long l=strlen(s); long long ans1=0; init(); for(int i=0;i<l;i++) { if(s[i]=='0'||s[i]=='5') ans1=(ans1+p[i])%N; } long long q=(p[l]-1+N)%N; q=f(q,N-2,N)%N;//分母 long long tmp=(f(p[l],k,N)-1+N)%N;//分子 tmp=(tmp*q)%N; cout<<(ans1*tmp)%N<<endl; return 0; }D题:给你一个图,只能在空地上建两种房子,blue,red,而建red的时候必须有blue相邻,并且可以拆房子然后再重建,blue人口容量100,red人口容量200,求怎样才能是的人口容量最大。
小结:直接用dfs()搞,开始把所有的房子都建成blue,回溯的时候在把房子拆了建成red,最开始的房子不拆。
代码:
#include<iostream> #include<cstdio> #define maxn 505 using namespace std; int n,m; char s[maxn]; int map[maxn][maxn],vis[maxn][maxn]; int count=1; struct node { int x,y; char a; }p[1000005]; int xx[]={0,0,1,-1}; int yy[]={-1,1,0,0}; bool inmap(int x,int y) { if(1<=x&&x<=n&&1<=y&&y<=m) return true; else return false; } void dfs(int x,int y) { int nx,ny; for(int i=0;i<4;i++) { nx=x+xx[i],ny=y+yy[i]; if(inmap(nx,ny)&&(vis[nx][ny]==0)&&map[nx][ny]==0) { p[count].a='B'; p[count].x=nx,p[count].y=ny,count++; vis[nx][ny]=1; dfs(nx,ny); p[count].a='D'; p[count].x=nx,p[count].y=ny,count++; p[count].a='R'; p[count].x=nx,p[count].y=ny,count++; } } } int main() { int l; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%s",s); for(int j=0;j<m;j++) { if(s[j]=='.') map[i][j+1]=0; else map[i][j+1]=1; } } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if(vis[i][j]==0&&map[i][j]==0) { vis[i][j]=1; p[count].a='B'; p[count].x=i,p[count].y=j,count++; dfs(i,j); } } } printf("%d\n",count-1); for(int i=1;i<count;i++) { printf("%c %d %d\n",p[i].a,p[i].x,p[i].y); } return 0; }E题:给你一串数,从0开始,每次选某个数,然后向前移动ai长度,这里有些位置不能走,最后问你走到总长度的路有多少条。
小结:很裸的状压dp,不过得用sum数组优化下。
dp[i]=sum{dp[i^(1<<j]};i与j只相差一位,即i能通过i^(1<<j)增加aj转移过来。
代码:
#include<iostream> #include<cstdio> #define N 1000000007 #define maxn 1<<25 using namespace std; int n,k; int a[25],b[3],dp[maxn],sum[maxn]; int DP() { dp[0]=1;//只能从0开始 for(int i=1;i<(1<<n);i++) { //求出当前状态所在的位置 sum[i]=0; int p; for(int j=0;j<n;j++) { if(i&(1<<j)) { p=j;//从小到大找第一个为1的位置 break; } } sum[i]=sum[i^(1<<p)]+a[p];//去掉这个位置的状态一定已经访问过 //判断当前位置是否可以停留 int flag=0; for(int j=0;j<k;j++) { if(sum[i]==b[j]) { flag=1; break; } } //不可以的话,直接忽略,当前的路径和为0 if(flag==1) continue; //动态转移 for(int j=0;j<n;j++) { if(i&(1<<j)) { dp[i]+=dp[i-(1<<j)]; if(dp[i]>N)//这里没用% dp[i]-=N; } } } return dp[(1<<n)-1]; } int main() { scanf("%d",&n); for(int i=0;i<n;i++) { scanf("%d",&a[i]); } scanf("%d",&k); for(int i=0;i<k;i++) scanf("%d",&b[i]); printf("%d\n",DP()); return 0; }