muti多校-3
HDU 6058
题目要求
求数组中所有连续区间的k大数之和
参考AC代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| typedef long long ll; const int N=500010; int Case,n,K,i,a[N],pos[N],pre[N],nxt[N]; ll ans; inline void del(int i){ pre[nxt[i]]=pre[i]; nxt[pre[i]]=nxt[i]; } inline ll solve(int x){ static int a[100],b[100]; int i,ca=0,cb=0; for(i=x;i;i=pre[i]){ a[++ca]=i-pre[i]; if(ca==K)break; } for(i=x;i<=n;i=nxt[i]){ b[++cb]=nxt[i]-i; if(cb==K)break; } ll t=0; for(i=1;i<=ca;i++)if(K-i+1<=cb) t+=1LL*a[i]*b[K-i+1]; return t; } int main(){ // freopen("input.txt","r",stdin); scanf("%d",&Case); while(Case--){ scanf("%d%d",&n,&K); for(i=1;i<=n;i++)scanf("%d",&a[i]),pos[a[i]]=i; for(i=0;i<=n+1;i++)pre[i]=i-1,nxt[i]=i+1; pre[0]=0; nxt[n+1]=n+1; ans=0; for(i=1;i<=n;i++){ int x=pos[i]; ans+=solve(x)*i; del(x); } printf("%lld\n",ans); } }
|
思路
用双向链表模拟
pre和next模拟指针
对数字hash处理记录位置 从1开始处理 处理好之后把1删除处理2 因为1对2的处理没有影响 后续相同
删除操作需要修改pre和next数组
对于每个位置预处理左边和右边比它大的k个数字
注意:i==1表示向左取一个段 并未取到端点 若a[i]=1表示左端点未取 自然做乘法操作时乘1
若a[i]>1表示中间有小于它的数字 自然有a[i]种情况
a和b代表段长并未是总长 因为如i取到2 说明必取1个点 所以能变化的区间只有这个点的后面的段了
综上 i是取的段数并未取段末的点 所以不能在k==1时break 也需要用k+i-i来判断右边的段数
HDU 6060
题目要求
给出一颗n个节点的树,要求将2-n号节点分成k部分,然后再将每一部分加上1号节点,定义每一部分的val为其中的点在原图上的最小斯坦纳树,问总的val最大可能是多少。
参考AC代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| const double eps = 1e-6; const LL mod=1e9+7; const LL INF=(LL)1e18; using namespace std; LL gcd(LL a,LL b){return b==0?a:gcd(b,a%b);} LL qpow(LL x,LL y){LL re=1,base=x%mod;while(y){if(y&1)re=(re*base)%mod;base=(base*base)%mod;y>>=1;}return re;} int n,k; LL ans; int sz[maxn]; struct node{ int to,w; node(int to,int w):to(to),w(w){} }; vector<node>e[maxn]; void dfs(int id,int fa,int ww){ sz[id]=1; for(int i=0;i<e[id].size();i++){ int next=e[id][i].to,we=e[id][i].w; if(next==fa) continue; dfs(next,id,we); sz[id]+=sz[next]; } int temp=min(k,sz[id]); ans+=(LL)ww*(LL)temp; } int main(){ // freopen("input.txt","r",stdin); // freopen("ouput.txt","w",sdout); ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); while(cin>>n>>k){ for(int i=0;i<=n;i++) e[i].clear(); mm(sz,0),ans=0; for(int i=1;i<=n-1;i++){ int x,y,z; cin>>x>>y>>z; e[x].pb(node(y,z)); e[y].pb(node(x,z)); } dfs(1,0,0); cout<<ans<<endl; } return 0; }
|
思路
ans开LL
HDU 6063
题目要求
计算
期中u为莫比乌斯函数
参考AC代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| const double eps = 1e-6; const LL mod=1e9+7; const LL INF=(LL)1e18; using namespace std; LL gcd(LL a,LL b){return b==0?a:gcd(b,a%b);} LL qpow(LL x,LL y){LL re=1,base=x%mod;while(y){if(y&1)re=(re*base)%mod;base=(base*base)%mod;y>>=1;}return re;} int flag=1; int main(){ // freopen("input.txt","r",stdin); // freopen("ouput.txt","w",sdout); ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); LL n,k; while(cin>>n>>k){ cout<<"Case #"<<flag++<<": "; n%=mod; cout<<qpow(n,k)<<endl; } return 0; }
|
思路
打表可以发现答案就是n^k
注意n需要先mod
HDU 6066
题目要求
求数组中小于等于35的个数
参考AC代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| const double eps = 1e-6; const LL mod=1e9+7; const LL INF=(LL)1e18; using namespace std; LL gcd(LL a,LL b){return b==0?a:gcd(b,a%b);} LL qpow(LL x,LL y){LL re=1,base=x%mod;while(y){if(y&1)re=(re*base)%mod;base=(base*base)%mod;y>>=1;}return re;} int main(){ // freopen("input.txt","r",stdin); // freopen("ouput.txt","w",sdout); ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); int t; cin>>t; int sum=0; for(int i=1;i<=t;i++){ int x; cin>>x; if(x<=35) sum++; } cout<<sum<<endl; return 0; }
|
思路
水题