水題合集
阿新 • • 發佈:2019-02-08
HDU 5101
題意:n個班級 第i個班級有num[i]個人,第j個人的戰鬥力為v[i][j].
n<=1e3,num[i]<=100,v[i],k<=1e9.問從n個班級中選兩個人其戰鬥力和>k並且兩個人不在同一班時的方案數?
把所有人的戰鬥裡存到某個陣列b中 然後將b排序.
列舉第一個人為第i個班級第j個人,其戰鬥力為x,
則快速找到b中第一個>k-x的位置pos 則a[i][j]貢獻tot-pos+1.然後在a[i]中二分,扣掉同一班級的即可.
O(n*m log tot) (a,b),(b,a)都被列舉 答案最後除以2
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e3+5; ll a[N][110],num[N],b[N*N]; int main() { int T; cin>>T; while(T--) { ll n,k,tot=0; scanf("%lld%lld",&n,&k); for(int i=1;i<=n;i++) { scanf("%lld",&num[i]); for(int j=1;j<=num[i];j++) scanf("%lld",&a[i][j]),b[++tot]=a[i][j]; sort(a[i]+1,a[i]+1+num[i]); } sort(b+1,b+1+tot); ll ans=0; for(int i=1;i<=n;i++) { for(int j=1;j<=num[i];j++) { ll x=k-a[i][j]+1; ll pos=lower_bound(b+1,b+1+tot,x)-(b+1)+1; ans+=(tot-pos+1ll); ll same=lower_bound(a[i]+1,a[i]+1+num[i],x)-(a[i]+1)+1; ans-=(num[i]-same+1ll); } } printf("%lld\n",ans/2); } return 0; }
HDU 5056
題意:給出字串s,問s中有多少個子串滿足:子串中每個字元的出現次數不超過k,|s|,k<=1e5.
列舉[le,rg] 當rg不合法時 從[le+1,rg]繼續開始列舉,雙指標弄一弄即可
HDU 5167#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=2e5+5; char s[N]; int num[30]; int main() { int T,k; cin>>T; while(T--) { memset(num,0,sizeof(num)); scanf("%s%d",s+1,&k); int n=strlen(s+1),rg=1; long long ans=0; for(int le=1;le<=n;le++) { while(rg<=n) { if(num[s[rg]-'a']<k) num[s[rg]-'a']++,rg++; else break; } ans+=rg-le; num[s[le]-'a']--; } cout<<ans<<endl; } return 0; }
題意:T次詢問,每次給出一個數x,問x是否能寫成若干個fib數的乘積.T<=1e5,x<=1e9
fib數增長恨快,不大於1e9的fib只有45個.
暴力列舉乘積中的第一個fib數f[i],然後遞迴判定dfs(n/f[i])是否有解即可.
每次n至少減小一半 每層列舉45個數 最壞45個分支,O(T*45*45*logn).
加個小優化 預處理出可以能是n因子的fib數(應該能晒的只剩10個左右),然後判斷該因子用幾次即可.
實際的複雜度應該比較小
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=2e2+2; int T,n,num; ll f[N],h[N]; bool ans; void init() { int i; f[1]=f[2]=1; for(i=3;i<=45;i++) { f[i]=f[i-1]+f[i-2]; if(f[i]>1e9) break; // cout<<f[i]<<' '; } num=i; } bool dfs(int cur,int n) { if(ans) return true; if(n==1) { ans=true; return true; } if(cur>num) return false; if(dfs(cur+1,n)) return true; int i=cur; while(n%h[i]==0) { if(dfs(cur+1,n/h[i])) return true; n/=h[i]; } return false; } int main() { init(); cin>>T; while(T--) { ans=false; scanf("%d",&n); int pn=0; for(int i=3;i<=45;i++) if(n%f[i]==0) h[++pn]=f[i]; num=pn; if(n==1||n==0) { printf("Yes\n"); continue; } ans=dfs(1,n); printf(ans?"Yes\n":"No\n"); } return 0; }
HDU 5163
題意:n個車站 第i個車站和第i+1個車站距離為d[i],
m次詢問,當bus從車站((j-1)%modn+1)出發,第j個人從x[j]坐到y[j]的最短時間. bus開到n後掉頭.
n,m<=1e5,d[i]<=1e9.
分情況討論即可.設bus出發點為s,人的起點終點為[x,y],pre[i]為第i個人距離起點位置.
當x<y時
當s<x 則ans=pre[y]-pre[s].
當x<s<y || s>y 則ans=suf[s]+tot+pre[y]
當x>y時
當s>x || y<s<x || s<y則ans=suf[s]+suf[y]
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5,inf=0x3f3f3f3f;
ll d[N],a[N],pre[N],suf[N];
int main()
{
int T,n,m;
cin>>T;
while(T--)
{
scanf("%d%d",&n,&m);
ll tot=0;
memset(a,0,sizeof(a));
memset(pre,0,sizeof(pre));
memset(suf,0,sizeof(suf));
for(int i=2;i<=n;i++)
scanf("%lld",&d[i]),a[i]=a[i-1]+d[i],tot+=d[i];
for(int i=1;i<=n;i++)
pre[i]=pre[i-1]+(a[i]-a[i-1]);
for(int i=n-1;i>=1;i--)
suf[i]=suf[i+1]+(a[i+1]-a[i]);
for(int j=1;j<=m;j++)
{
int s=(j-1)%n+1;
int x,y;
ll ans;
scanf("%d%d",&x,&y);
//cout<<s<<' ';
if(x<y)
{
if(s<=x)
ans=pre[y]-pre[s];
else
ans=suf[s]+tot+pre[y];
}
else
ans=suf[s]+suf[y];
printf("%lld\n",ans);
}
}
return 0;
}
題意:長度為n的序列a,操作:交換任意兩個元素,
問操作正好一次的情況下 最多能得到多少種不同的序列? n,a[i]<=1e5.
假如序列元素都不同 則答案為C(n,2) 現在只要扣掉選相同元素的方案數即可.
注意 有相同元素才能得到原來的序列.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
ll b[N];
int main()
{
int T;
cin>>T;
while(T--)
{
ll n;
int x;
memset(b,0,sizeof(b));
scanf("%I64d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&x),b[x]++;
ll ans=n*(n-1)/2;
int flag=0;
for(int i=1;i<N;i++)
{
ans-=(b[i]*(b[i]-1))/2;
if(b[i]>=2)
flag=1;
}
printf("%I64d\n",ans+flag);
}
return 0;
}