【SCAU 16校赛】 18108 规律 O(n)法 预处理

37 篇文章 0 订阅
32 篇文章 3 订阅

Description
Chocola is addicted to a phone game named white grid. There’s a cross with 5 empty grids on the game interface.
Chocola can write 5 different numbers ranging between 1 and n (inclusive) into grids.
When the sum of 3 horizontal grids is equal to the sum of 3 vertical grids, Chocola can earn some score.
Then grids will be clear and Chocola can start the game again.
But the game system doesn’t allow Chocola to earn score by the same cross.
Vanilla also play this game and she can play the game again and again.
Chocola can’t understand why Vanilla is so skillful?
How many times has Vanilla played?!
Now Chocola wonders how many ways can she earn score.
±–+
| |
±–±--±–+
| | | |
±–±--±–+
| |
±–+

输入格式
The input file begins with an integer T (T <= 10) in one row indicating the number of test case.
Then T lines follow, one test case per line. Each line consists of an positive integer n (1 <= n <= 100)

输出格式
For each test case, print one line containing the answer.

输入样例
2
5
6

输出样例
24
112

题意:求题给方格中横纵填不同数使得横纵和相等的填法

思路(规律):

标签“暴力”害人不浅啊。。。dfs了几次都TL了。静下心来观察了一下规律,其实O(n)就可以过了。
1.五个格子,n<=4肯定没有解,输出0。
2.n>=5时,宏观的规律就是中间的先不管(公共嘛),找到四个数满足横纵和相等,然后四个数横方向可以两两交换,纵方向可以两两交换,横纵同时还可以交换,所以拿到一个四元组其结果就是ans += 2x2x2x(n-4)。为什么要多乘上一个(n-4)?这就是中间那个。你拿了四个数,你的n又比4大,所以随便找一个剩下来的数放中间就行了。
3.现在看这个四元组怎么选。这个时候就枚举加和结果的目标数就行了。最后不是sum = a+b = c+d吗,我们就枚举这个sum,然后就是一个小学知识——把一个数拆分成两个数的和,然后选出两组来当ab和cd即可。
就比如样例的5得出24是这么来的:
在这里插入图片描述
4.那么目前规律就很显而易见了。我们先预处理一下1->200之间的可能被当做加和结果的数,这些数能拆分成 i/2个(若是偶数要舍去一个含相同项的)。然后每次case拿到一个n就从5到200之间枚举目标数即可。时间复杂度O(n)。

AC代码:

#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include <queue>
#include<sstream>
#include <stack>
#include <set>
#include <bitset>
#include<vector>
#define FAST ios::sync_with_stdio(false)
#define abs(a) ((a)>=0?(a):-(a))
#define sz(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define mem(a,b) memset(a,b,sizeof(a))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define rep(i,a,n) for(int i=a;i<=n;++i)
#define per(i,n,a) for(int i=n;i>=a;--i)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<ll,ll> PII;
const int maxn = 3e4+2;
const int inf=0x3f3f3f3f;
const double eps = 1e-7;
const double pi=acos(-1.0);
const int mod = 1e9+7;
inline int lowbit(int x){return x&(-x);}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){if(!b){d=a,x=1,y=0;}else{ex_gcd(b,a%b,d,y,x);y-=x*(a/b);}}//x=(x%(b/d)+(b/d))%(b/d);
inline ll qpow(ll a,ll b,ll MOD=mod){ll res=1;a%=MOD;while(b>0){if(b&1)res=res*a%MOD;a=a*a%MOD;b>>=1;}return res;}
inline ll inv(ll x,ll p){return qpow(x,p-2,p);}
inline ll Jos(ll n,ll k,ll s=1){ll res=0;rep(i,1,n+1) res=(res+k)%i;return (res+s)%n;}
inline ll read(){ ll f = 1; ll x = 0;char ch = getchar();while(ch>'9'||ch<'0') {if(ch=='-') f=-1; ch = getchar();}while(ch>='0'&&ch<='9') x = (x<<3) + (x<<1) + ch - '0',  ch = getchar();return x*f; }
int dir[4][2] = { {1,0}, {-1,0},{0,1},{0,-1} };

ll n;
ll ans = 0;
ll dp[250];

int main()
{
    int kase;
    scanf("%d",&kase);
    rep(i,5,200) dp[i] = i/2 - (i%2==0);    //预处理,偶数减去一个含相同项的。
    while(kase--)
    {
        n = read();  ans = 0;
        if(n<5) ans = 0;        //小于5无解
        else
        {
            rep(i,5,200)        //枚举目标数
            {
                ll cur =  dp[i] - max( 1,(i-n) )+1 ;        //每次能选到的对
                if(cur==1) continue;
                if(cur==0) break;
                ans += (cur-1)*cur*2*2*(n-4);       //C(n,2)*2*2*2*(n-4)
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值