首先.这次开局烂到家了,1200+人过了的03签到题,我队还一直在MLE中,因为怕超时,复杂度算不清不敢暴力.
最后还是过了07 05 04 之后才稳一点慢慢的改一点交一点 ...罚时爆炸的过了03..
这个题真的暴力也能过?还飞快.暴力不是 n3 吗. 哦不,好像并不是n3的.
这个题内存卡的比较紧,直接一个bool 类型了.
当时这个签到题我们队是最后出的,卡了很久,我一开始想并查集最后被推翻了,然后队友想了 最大团来做.然后就一直MLE.我最后写了个暴力,寻思直接是n3 我用两个vector 来存有边的和无边的,两种情况分别找,然后还想这记录1的个数多,还是0的个数多.来优化常数,可惜 都没用!!!因为MLE。。。
当时可能看到1200+人过有点不淡定了...没想到这么优雅的暴力呢.
PS: 主要是这个题目有个定理,保证6个点以上一定bad,所以很快就退出.
#include<iostream>
#include<cstdio>
#include<string.h>
using namespace std;
const int maxn = 3e3;
bool w[maxn][maxn];
bool flag(int n)
{
for(int i = 1; i <= n; ++ i)
{
for(int j = i + 1; j <= n; ++ j)
{
for(int k = j + 1; k <= n; ++ k)
{
if(w[i][j] == w[i][k] && w[i][k] == w[j][k] && w[i][j] == w[j][k])
return true;
}
}
}
return false;
}
int main()
{
int t, n, m;
scanf("%d", &t);
while(t --)
{
scanf("%d", &n);
for(int i = 1; i < n; ++ i)
{
for(int j = 1 + i; j <= n; ++ j)
{
scanf("%d", &m);
if(m == 1)
w[j][i] = w[i][j] = false;
else
w[j][i] = w[i][j] = true;
}
}
if(flag(n))
printf("Bad Team!\n");
else
printf("Great Team!\n");
}
return 0;
}
队友的xjb做法:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
#include<cstdio>
#include<cstring>
#define N 3005
bool flag[N], a[N][N];
int ans, cnt[N], group[N], n, vis[N];
bool dfs( int u, int pos ){
if(ans >= 3) return 1;//因为递归层数太多,所以这里加了个剪枝....
int i, j;
for( i = u+1; i <= n; i++){
if( cnt[i]+pos <= ans ) return 0;
if( a[u][i] )
{
for( j = 0; j < pos; j++ ) if( !a[i][ vis[j] ] ) break;
if( j == pos )
{
vis[pos] = i;
if( dfs( i, pos+1 ) ) return 1;
}
}
}
if( pos > ans )
{
for( i = 0; i < pos; i++ )
group[i] = vis[i];
ans = pos;
return 1;
}
return 0;
}
void maxclique()
{
ans=-1;
for(int i=n;i>0;i--)
{
vis[0]=i;
dfs(i,1);
cnt[i]=ans;
}
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
memset(a, 0, sizeof(a));
scanf("%d", &n);
for(int i = 1; i <= n-1; i++)
{
for(int j = 1; j <= n-i; j++)
{
scanf("%d", &a[i][i+j]);
a[i+j][i] = a[i][i+j];
}
}
int ans1, ans2;
maxclique();
ans1 = ans;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
a[i][j] = !a[i][j];
maxclique();
ans2 = ans;
if(ans1 >= 3 || ans2 >= 3) puts("Bad Team!");
else puts("Great Team!");
}
return 0;
}
队友过得,我还没学会,正解好像是扩展KMP?也可能是他瞎搞的
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 2e6+10;
const int mod = 1e9+7;
char str[maxn], str1[maxn], str2[maxn];
int len, len3;
int nt[maxn], nt3[maxn];
ll res[maxn], res3[maxn];
void getNext1()
{
nt[0] = -1;
int i = 0, j = -1;
while (i <= len)
{
if (j == -1 || str[i] == str[j])
nt[++i] = ++j;
else
j = nt[j];
}
}
void getNext2()
{
nt3[0] = -1;
int i = 0, j = -1;
while (i <= len3)
{
if (j == -1 || str2[i] == str2[j])
nt3[++i] = ++j;
else
j = nt3[j];
}
}
int main()
{
int t;
cin >> t;
while(t--)
{
memset(res, 0, sizeof(res));
memset(res3, 0, sizeof(res3));
memset(nt, 0, sizeof(nt));
memset(nt3, 0, sizeof(nt3));
scanf(" %s %s", str1, str2);
int len1 = strlen(str1);
int len2 = strlen(str2);
for(int i = 0; i < len1/2; i++)
swap(str1[i], str1[len1-i-1]);
for(int i = 0; i < len2; i++)
str[len2-i-1] = str2[i];
str[len2] = '#';
for(int i = len2+1; i < len1+len2+1; i++)
str[i] = str1[i-len2-1];
str[len1+len2+1] = 0;
len = len1+len2+1;
len3 = len2;
// cout << str << endl;
getNext1();
for(int i = 0; i < len2/2; i++)
swap(str2[i], str2[len2-i-1]);
getNext2();
// cout << str << endl;
ll ans = 0;
// int len = len1+len2+1;
for(int i = len; i >= 1; i--)
{
res[i]++;
res[nt[i]] += res[i];
}
for(int i = len3; i >= 1; i--)
{
res3[i]++;
res3[nt3[i]] += res3[i];
}
// cout << str << ' ' << str2 << endl;
// for(int i = 1; i <= len2; i++)
// cout << res[i] << ' ' << res3[i] << endl;
for(ll i = 1; i <= len2; i++)
{
// cout << i << ' ' << res[i] << endl;
ans = (ans+(res[i]-res3[i])*i)%mod;
}
printf("%lld\n", ans);
}
return 0;
}
hdu 6154 &&1005 CaoHaha's staff
正解找规律. 但是我队找规律比较菜啊....
我是用了二分做的...
当然这个题目数据在大点 可能就要二分了吧。。
首先我看到题目的时候...好久队友给我讲明白了题意,我看求最小,立马套二分啊,诶 ?满足单调性.即走k步可以凑出的面积 k+1 步一定也可以啊.
好,那么就像怎么check,这个check其实感觉就好找到的规律差不多了,首先我要想使面积最大,我肯定优先走对角线,因为横着和斜着斜着每次增加 根2的长度.那么对于相同的步数的话,我肯定要是长宽越接近凑出的面积尽可能的大. 那么我先考虑步数为偶数的情况,对于二分到的步数先均分给四个边,因为是偶数,%4一定是2或0了,如果余2 那么我就可以使两个对边长度在增加1 ,这时的面积为 ch *ku *2. 然后我发现对于步数比他多1的奇数来说,他所能得到的面积正是在原来的四边形上在多扩展一个等腰梯形,且步数正好多1.所以我check就判断了奇数和偶数来check了,
至于为什么是一定多一步的,从最后一个样例5为7可以看出来为什么,然后多画几个结论就得到了.
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn = 1e5 + 10;
typedef long long ll;
ll n;
int check(ll x)
{
ll res = x;
if(x & 1)
res --;
ll len = res / 4;
ll ch ,ku;
ch = ku = len;
if(res % 4)
ch++;
ll s = 0;
if(x % 2 == 0)
{
s = ch * ku * 2;
}
else
{
double ss = 0.5 * (2*ch - 1);
// cout<<x<<' '<<ss<<endl;
s = ch * ku * 2 + (ll)ss;
//cout<<s<<endl;
}
if(s >= n)
return 1;
return 0;
}
int main()
{
int t;
cin>>t;
while(t--)
{
scanf("%lld",&n);
ll l = 0,r = 2*1e9,mid,ans;
while(l <= r)
{
mid = (l + r) >> 1;
if(check(mid))
r = mid - 1,ans = mid;
else
l = mid + 1;
}
//check(7);
// puts("");
// check(6);
printf("%lld\n",ans);
}
return 0;
}
hdu 6156 && 1007 Palindrome Function
2 -36 进制中 (L,R ) 回文数有多少个
让你求(l,r)满足条件的数有多少啊..这不很明显数位dp,算了复杂度,足够了.枚举每种进制,剩下的求法和10进制回文数有多少一样了.
我这里dp【i】【j】【k】【f】表示的是k进制下,串的起点是i,终点是j, 是否已经是回文串了.f 为0 表示否 1 表示 是
PS: 这里需要注意的就是前导0的问题,由于前导0的存在使得回文串的长度是不固定的,所以这里就设法解决前导0就好,另外需要开个中间数组记录一下前面填过的数,来判断回文
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn = 1e5 + 10;
typedef long long ll;
ll dp[50][50][50][5];
// dp【i】【j】【k】【f】表示的是k进制下,串的起点是i,终点是j,
// 是否已经是回文串了. f 为0 表示否 1 表示 是
int num[50],temp[50];
//temp 中间数组 ,用来判断回文
ll dfs(int start,int cur,int state,int fp,int base)
//start 字符串起点,也用来确定第一个非前导0的位置.cur 当前处理到第几位
//state 是否是回文串.
// base 进制
{
if(cur<0)
return state;
if(!fp&&dp[start][cur][base][state]!=-1)
return dp[start][cur][base][state];
int fpmax = fp ? num[cur] : (base-1);
ll ret = 0;
for(int i = 0;i <= fpmax;i++)
{
temp[cur] = i;//确定该位的值
if(start == cur&&i == 0)// 前导0
ret+=dfs(start-1,cur-1,state,fp && i == fpmax,base);
else if(state&&cur<(start+1)/2)//小于一半了,说明要开始判断是否回文了
ret+=dfs(start,cur-1,temp[start-cur]==i,fp&&i==fpmax,base);
else//未构成回文串就继续处理下一位.
ret+=dfs(start,cur-1,state,fp&&i==fpmax,base);
}
if(!fp)
dp[start][cur][base][state]=ret;
return ret;
}
ll solve(ll n,int k)
{
int len=0;
while(n)
{
num[len++]=n%k;
n/=k;
}
num[len]=0;
return dfs(len-1,len-1,1,1,k);
}
int main()
{
int _;
cin>>_;
ll L,R;
int l,r;
ll ans1,ans2,ans,ans3;
int t=1;
memset(dp,-1,sizeof dp);
while(_--)
{
ans = 0;
scanf("%lld %lld %d %d",&L,&R,&l,&r);
for(int i = l;i <= r;i++)
{
ans1 = solve(L-1,i);
ans2 = solve(R,i);
ans3 = ans2 - ans1;
ans += ans3*i + (R - L + 1 - ans3);
}
printf("Case #%d: %lld\n",t++,ans);
}
return 0;
}