解法:暴力模拟+贪心
#include<bits/stdc++.h> using namespace std; int a[110][110]; int main(){ int n,k,cmp,f=0;scanf("%d%d",&n,&k); if(k>n*n){puts("-1");return 0;}cmp=n; int r=1; while(k>=2*cmp-1){ k-=2*cmp-1;cmp-=1; for(int i=1;i<=n;i++) a[r][i]=a[i][r]=1; r++; if(k==0) break; } if(k==0){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ cout<<a[i][j]<<" "; } cout<<endl; } return 0; } if(k&1){ a[r][r]=1;k-=1; k/=2; for(int i=r+1;i<=r+k;i++) a[r][i]=a[i][r]=1; } else{ a[r+1][r+1]=a[r][r]=1;k-=2;k/=2; for(int i=r+1;i<=r+k;i++) a[r][i]=a[i][r]=1; } for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ cout<<a[i][j]<<" "; } cout<<endl; } return 0; }
解法:正着扫一遍,倒着扫一遍记录答案就好
#include<bits/stdc++.h> using namespace std; const int N=2e5+10; int a[N],ans[N]; set<int>se; int main(){ int n;scanf("%d",&n);se.insert(1e8); for(int i=1;i<=n;i++) {scanf("%d",&a[i]);ans[i]=1e8;} int tmp=-1; for(int i=1;i<=n;i++){ if(a[i]==0) tmp=i,ans[i]=0; else{ if(tmp!=-1) ans[i]=i-tmp; } } tmp=-1; for(int i=n;i>=1;i--){ if(a[i]==0) tmp=i,ans[i]=0; else{ if(tmp!=-1) ans[i]=min(ans[i],tmp-i); } } for(int i=1;i<=n;i++) printf("%d ",ans[i]); return 0; }
题意:构造n个数,使得他们的和为一个数,且gcd最大
解法:sqrt(n)处理最大gcd,构造 gcd*(1+2+...+n-1+k) k=sum/gcd-(n-1)*n/2;
#include<bits/stdc++.h> using namespace std; typedef long long ll; ll n,k; ll max_(ll a,ll b) {return a>b?a:b;} int main(){ scanf("%I64d%I64d",&n,&k); if(k>=1e6){puts("-1");return 0;} int ans=-1;ll cmp=k*(k+1)/2; for(ll i=1;i*i<=n;i++){ if(n%i) continue; if(n/i>=cmp) ans=max_(ans,i); if(i>=cmp) ans=max_(ans,n/i); } if(ans==-1){puts("-1");return 0;} ll cnt=n/ans; for(ll i=1;i<k;i++){ printf("%I64d ",i*ans); cnt-=i; } printf("%I64d\n",cnt*ans); return 0; }
解法:答案具有单调性,二分答案即可
#include<bits/stdc++.h> using namespace std; const int N=1e6+10; char s[N];int a[N];int k,cnt; bool ok(int x){ int sum=0,res=0; for(int i=0;i<=cnt;i++){ sum+=a[i]; if(a[i]>x) return 0; if(sum>x){res++;sum=a[i];} } if(sum) res++; if(res>k) return 0; return 1; } int main(){ scanf("%d",&k);getchar();gets(s);int p=0; for(int i=1;s[i];i++){ if(s[i]==‘ ‘||s[i]==‘-‘) a[cnt++]=(i-p+1),p=i+1; } a[cnt]=strlen(s)-p; int l=1,r=N;int mid,ans=N; while(l<=r){ mid=(l+r)>>1; //cout<<l<<" "<<r<<" "<<ans<<endl; if(ok(mid)) ans=min(ans,mid),r=mid-1; else l=mid+1; } printf("%d\n",ans); return 0; }
解法:考虑n^2的dp,dp[n][k]代表胜积分为k是否可行,然后最后dfs记录答案即可
#include<bits/stdc++.h> using namespace std; const int N=1100; bool dp[N][2*N]; char ans[N];int n,k;string s; void dfs(int x,int k){ //cout<<x<<" "<<k<<endl; if(x==0) return; if(s[x]==‘L‘&&dp[x-1][k-1]) dfs(x-1,k-1); else if(s[x]==‘W‘&&dp[x-1][k+1]) dfs(x-1,k+1); else if(s[x]==‘D‘&&dp[x-1][k]) dfs(x-1,k); else{ if(dp[x-1][k-1]) ans[x]=‘L‘,dfs(x-1,k-1); else if(dp[x-1][k+1]) ans[x]=‘W‘,dfs(x-1,k+1); else if(dp[x-1][k]) ans[x]=‘D‘,dfs(x-1,k); } } int main(){ std::ios::sync_with_stdio(false); cin>>n>>k>>s;s=‘0‘+s;dp[0][k+1]=1; //k+1 ????0 //1 ????-k //2*k+1 ????k for(int i=1;i<=n;i++){ for(int j=1;j<=2*k+1;j++){ if(s[i]==‘L‘) dp[i][j]=dp[i-1][j-1]; else if(s[i]==‘W‘) dp[i][j]=dp[i-1][j+1]; else if(s[i]==‘D‘) dp[i][j]=dp[i-1][j]; else dp[i][j]=max({dp[i-1][j+1],dp[i-1][j-1],dp[i-1][j]}); if(i!=n) dp[i][1]=0,dp[i][2*k+1]=0; } } if(!dp[n][2*k+1]&&!dp[n][1]) {puts("NO");return 0;} if(dp[n][2*k+1]){dfs(n,2*k+1);} else dfs(n,1); for(int i=1;i<=n;i++) if(s[i]!=‘?‘) ans[i]=s[i]; for(int i=1;i<=n;i++) printf("%c",ans[i]);printf("\n"); return 0; }
题意:对于给定的序列,问有多少子序列的gcd为1
解法:考虑到题目的范围,即1e5的范围内约数大约有200,1e9的范围约数大约有800个,然后枚举gcd,从总答案里面减去就好,因为约数有容斥的地方,所以考虑用莫比乌斯反演,应用答案约数之间的关系可求解
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e5+10; int mbs[N],vis[N],p[N]; const int mod=1e9+7; ll pow_(int a,int b){ ll res=1,tmp=a; while(b){ if(b&1) (res*=tmp)%=mod; b/=2; (tmp*=tmp)%=mod; } return res; } void mobius(){ mbs[1]=1;int cnt=0; for(int i=2;i<N;i++){ if(!vis[i]) p[++cnt]=i,mbs[i]=-1; for(int j=1;j<=cnt&&i*p[j]<N;j++){ vis[i*p[j]]=1; if(i%p[j]==0) {mbs[i*p[j]]=0;break;} mbs[i*p[j]]=-mbs[i]; } } } int cnt[N],a[N]; int main(){ int n;scanf("%d",&n);mobius();int m=0; for(int i=1;i<=n;i++) scanf("%d",&a[i]),m=max(m,a[i]); for(int i=1;i<=n;i++){ for(int j=1;j*j<=a[i];j++){ if(a[i]%j==0){cnt[j]++;if(a[i]!=j*j) cnt[a[i]/j]++;} } } ll ans=0; for(int i=1;i<=m;i++){ ll tmp=((pow_(2,cnt[i])+mod-1)%mod*mbs[i]%mod+mod)%mod; (ans+=tmp)%=mod; } printf("%I64d\n",ans); return 0; }
题意:有k个数,重复n次,组成的1e9的序列,区间修改+区间询问最小值
解法:ST表+线段树动态开点裸题
233
原文地址:https://www.cnblogs.com/vainglory/p/9735714.html
时间: 2024-09-29 15:23:58