暑期集训第三场

A.Ascending Rating HDU - 6319

这道题需要用到单调队列,然后结论是,区间[l,r]中,要反着push(a[i]),从r到l,然后此时deque.size()就是count,deque.front()就是maxrating。

#include<deque>
#include<iostream>
#include<queue>
#include<stack>
#define ll long long
using namespace std;
ll n, m, k, q, p, r, mod, t;
const int maxn = 1e7 + 50;
ll a[maxn];
deque<ll> d;

void push_in(ll x) {
	if (d.empty())
		d.push_back(x);
	else if ((!d.empty()) && x >= d.back()) {
		while ((!d.empty())&&x >= d.back())d.pop_back();//这里注意,empty一定要写,并且要写在前面
		d.push_back(x);
	}
	else d.push_back(x);
}

int main() {
	ios::sync_with_stdio(false);
	cin >> t;
	while (t--) {
		d.clear();

		ll suma = 0, sumb = 0;
		ll maxrating = -1, cnt = 0;
		cin >> n >> m >> k >> p >> q >> r >> mod;
		for (ll i = 1; i <= k; i++) {
			cin >> a[i];
		}
		for (ll i = k + 1; i <= n; i++) {
			a[i] = (p*a[i - 1] + q * i + r) % mod;
		}

		ll pos = n - m + 1;
		for (ll i = n; i>n - m; i--) {
			push_in(a[i]);
		}
		suma += (d.front() ^ pos);
		sumb += (d.size() ^ pos);
		pos--;
		ll j = n;

		for (ll i = pos; i>0; i--, j--) {
			if (a[j] == d.front())d.pop_front();
			push_in(a[i]);

			suma += (d.front() ^ i);
			sumb += (d.size() ^ i);
		}
		cout << suma << " " << sumb << endl;
		//system("pause");
	}
}

C.Dynamic Graph Matching HDU - 6321

这个题要用状压dp,dp[now] [s] 表示当前状态now中集合数为s的匹配数,然后就是神仙推出来的转移方程了

加一条边的时候:dp[now] [i] [((1<<from)|(1<<to))] += dp[pre] [i];

减一条边的时候:dp[now] [i] [((1<<from)|(1<<to))] -= dp[pre] [i];

#include <bits/stdc++.h>
#define maxn 2005
using namespace std;
const int mod=1e9+7;
int dp[2][maxn];///用滚动数组压缩
int cnt[maxn];
int ans[maxn];
char str[2];
int bit(int x){//获取某个数二进制位上有多少个1
    int cnt=0;
    while(x){
        if(x&1) cnt++;
        x>>=1;
    }
    return cnt;
}
void init(){//初始化处理二进制位上1的个数
    for(int i=0;i<1024;i++){
        cnt[i]=bit(i);
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    init();
    
    while(t--){
        int n,m;int now=1,pre=0;
        scanf("%d%d",&n,&m);
        int all=1<<n;
        memset(dp,0,sizeof(dp));
        dp[0][0]=1;
        while(m--){
            scanf("%s",str);
            int from,to;
            scanf("%d%d",&from,&to);
            from--,to--;
            int tmp=(1<<from)|(1<<to);//代表第from位和第to位有一条边
            for(int i=0;i<all;i++){//先进行状态转移
                dp[now][i]=dp[pre][i];
            }
            if(str[0]=='+'){
                for(int i=0;i<all;i++){
                    if(!(tmp&i)){//如果没加上
                        dp[now][i|tmp]=(dp[now][i|tmp]+dp[pre][i])%mod;
                    }
                }
            }
            else{
                for(int i=0;i<all;i++){
                    if(!(tmp&i)){//如果没减去
                        dp[now][i|tmp]=(dp[now][i|tmp]-dp[pre][i]+mod)%mod;
                    }
                }
            }
            memset(ans,0,sizeof(ans));
            for(int i=0;i<all;i++){//统计答案
                ans[cnt[i]]=(ans[cnt[i]]+dp[now][i])%mod;
            }
            for(int i=2;i<=n;i+=2){///一个匹配数需要2个点
                if(i!=2) cout<<" ";
                cout<<ans[i];
            }
            puts("");
          //  printf("%d %d\n",pre,now);
            pre^=1,now^=1;
         //   printf("%d %d\n",pre,now);
        }
    }
}

D.Euler Function HDU - 6322

结论:7及以上的结果是连着了,前面一个5。

#include<iostream>
using namespace std;
#define ll long long
ll n,x;
int main(){
    cin>>n;
    while(n--){
        cin>>x;
        if(x==1){
            cout<<5<<endl;
            continue;
        }
        else cout<<x+5<<endl;
    }
}

F.Grab The Tree HDU - 6324

因为是异或,所以还是比较好想,当二进制的最高位有奇数个时,Q一定赢,以此类推,可以得到结论:当所有的节点异或起来得到sum==0时,才会是平局,其他情况都是Q赢。

#include<iostream>
using namespace std;
int n,t,x,y,flag,val,temp;
int main(){
    ios::sync_with_stdio(false);
    cin>>t;
    while(t--){
        int sum=0;
        flag=0;
        cin>>n;
        for(int i=0;i<n;i++){
            cin>>val;
            sum=sum^val;
        }
        for(int i=1;i<n;i++){
            cin>>x>>y;
        }
        if(sum==0)cout<<"D"<<endl;
        else cout<<"Q"<<endl;
    }
}

L.Visual Cube HDU - 6330

没什么好说的,直接模拟

#include<iostream>
using namespace std;
int t,a,b,c;
int main(){
    ios::sync_with_stdio(false);
    cin>>t;
    while(t--){
        cin>>a>>b>>c;
        int len=(b+c)*2+1;
        int lenw=(a+b)*2+1;
        for(int i=0;i<len;i++,cout<<endl){
            int pos=0;
            if(i<2*b){
                for(int j=i;j<2*b;j++,pos++)cout<<'.';
                for(int j=0;j<a;j++,pos+=2){
                    if(i%2==0)cout<<"+-";
                    else cout<<"/.";
                }

            }
            if(i>=2*b){
                for(int j=0;j<a;j++,pos+=2){
                    if(i%2==0)cout<<"+-";
                    else cout<<"|.";
                }
            }
            if(i<=2*c){
                for(int j=pos;j<lenw;j++){
                    if(i%2==0){
                        if(j%2==0)cout<<'+';
                        else cout<<'.';
                    }else {
                        if(j%2==0)cout<<'|';
                        else cout<<'/';
                    }
                }
            }
            if(i>2*c){
                for(int j=pos;j<lenw-(i-2*c);j++){
                    if(i%2==0){
                        if(j%2==0)cout<<'+';
                        else cout<<'.';
                    }else {
                        if(j%2==0)cout<<'|';
                        else cout<<'/';
                    }
                }
                for(int j=0;j<i-2*c;j++)
                    cout<<'.';
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值