目录
总结:
今天开场2分钟刚确定两道签到题1011和1012忽然肚子疼,拿着手机冲去厕所并让队友把这两题翻译发出来,在蹲坑时想出了结论,恰好此时队友也想出来了。回来之后队友已经把第一道签到出了,另一个队友也把第二道签到思路想出来了,我就继续去开其他题,签完道之后是长达两个小时的坐牢,我和队友同时在开1003和1002,想了一个多小时只确定了一个稍微超一点复杂度的暴力,另外队友一直在写1002的搜索,两小时出头时我写了一发1003的暴力,不出意料的T了,放弃1003去看过题数正在增长的1009,过了一会队友告诉我1003用shuffle+卡时过了,遂队友1继续看1002搜索,我和另外一个队友开1009的计算几何,讨论了大概十五分钟,我就和另外一个队友确定了大致思路,并开始画图模拟并开始写代码,写好代码之后debug了几分钟后一发直接过。然后我就去看1001,留下两个队友对着他们1002的搜索代码debug,到最后我1001依旧没看懂题目,最后五分钟,队友找到了另外一个队友写的搜索判断边界的bug,在04:59:16交了第十四发,过了1002,五题rk164结束比赛。
题解:
1001 - String
题意:
,定义一个
,
的值为满足以下条件的正整数 x 的个数:
1.
2. (即G的前x元素与后x个元素组成的串相同,后面称这两个串为左串和右串)。
3. 左串和右串的公共部分长度(相交部分的长度)大于0且该长度
问所有 的
相乘的结果对998244352取模的结果是多少,即问
样例解释:
做法:
先用Z函数(扩展KMP)求出每个i开始的后缀的最长公共前缀(LCP),再用模意义下的差分数组,从中对从
到
(z函数的z数组从
)中的所有满足
的
都加上1,表示从当前位置开始的LCP对x的贡献。最后再对每个模意义下的差分数组做前缀和得到预处理后的每个
值,将所有
的值相乘并对
取模得到答案。(注意差分数组要稍微开大一丢丢)
从 开始是因为z数组表示从i开始的后缀的最长公共前缀,第一个
表示公共部分的前
个字符,第二个
表示公共部分的后
个字符,这
个字符是不属于公共部分的长度,因此我们要从非公共部分长度每次+k开始枚举到i后缀最长能到达的值
,表示从当前字符i开始能给这些字符贡献1个x,给这些值都加上1。
代码:
/*
author:wuzx
*/
#include<bits/stdc++.h>
#define ll long long
#define int long long
#define endl "\n"
#define P pair<int,int>
#define f first
#define s second
using namespace std;
typedef unsigned long long ull;
const int maxn=200010;
const int inf=0x3f3f3f3f;
const int mod=998244353;
int t;
int n,m,k;
vector<int> z_function(const string& ss)
{
int len=(int)ss.length();
vector<int> z(len,0);
for(int i=1,l=0,r=0;i<len;i++)
{
if(i<=r)
z[i]=min(r-i+1,z[i-l]);
while(i+z[i]<len&&ss[z[i]]==ss[i+z[i]])
z[i]++;
if(i+z[i]-1>r)
{
l=i;
r=i+z[i]-1;
}
}
return z;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>t;
while(t--)
{
string ss;
cin>>ss;
cin>>k;
int len=ss.length();
auto z=z_function(ss);
z[0]=len;
vector<vector<int>> a(k,vector<int>(len/k+3,0));
function<void(int,int)> change = [&](int l,int r)
{
if(l>r)
return;
int idx=l%k;
int l1=(l+k-1)/k;
int r1=l1+(r-l)/k;
a[idx][l1]+=1;
a[idx][r1+1]-=1;
};
vector<int> num(k,0);
for(int i=1;i<=len;i++)
num[i%k]++;
for(int i=1;i<=len/2+1;i++)
{
int l=(i-1)*2+k;
int r=i+z[i-1]-1;
change(l,r);
}
int ans=1;
for(int i=0;i<k;i++)
{
for(int j=1;j<=num[i];j++)
{
a[i][j]+=a[i][j-1];
int x=a[i][j]+1;
ans=(ans*x)%mod;
}
}
cout<<ans<<endl;
}
return 0;
}
1003 - Backpack
题意:
有n个物品和一个容量为m的背包,第i个物品体积为,价值为
,问在恰好装满背包情况下物品价值的最大异或和,若背包不能恰好装满,输出-1;
做法:
考虑使用动态规划解决, 表示在装入前i个物品后,异或和为j,容量为k的情况是否存在,则dp方程为
我们知道这样的复杂度是
的,因此我们可以考虑使用bitset将复杂度优化到
.
代码:
/*
author:wuzx
*/
#include<bits/stdc++.h>
#define ll long long
#define int long long
#define endl "\n"
#define P pair<int,int>
#define f first
#define s second
using namespace std;
typedef unsigned long long ull;
const int maxn=200010;
const int inf=0x3f3f3f3f;
const int mod=998244353;
int t;
int n,m,k;
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>t;
while(t--)
{
cin>>n>>m;
vector<bitset<1025>> dp(1025),g(1025);
dp[0][0]=1;
for(int i=1;i<=n;i++)
{
int x,y;
cin>>x>>y;
for(int j=0;j<1024;j++)
{
g[j]=dp[j];
g[j]<<=x;
for(k=0;k<1024;k++)
if(g[j][k])
cout<<k<<endl;
}
for(int j=0;j<1024;j++)
dp[j]|=g[j^y];
}
int ans=-1;
for(int i=1023;i>=0;i--)
{
if(dp[i][m])
{
ans=i;
break;
}
}
cout<<ans<<endl;
}
return 0;
}
1009 - Laser
题意:
在一个二维坐标系中,有n个敌人,你可以在坐标系中的任何一个坐标中放置一门激光炮,激光炮的射程为任意值,方向可以射向米子型的八个方向,问是否存在一个放置激光炮的位置,使所有的敌人都能被消灭。
做法:我们先假设第一个敌人所在的点为激光炮放置点,遍历剩余个敌人寻找这个点攻击不到的一个点作为第二个点,如果找不到第二个点,说明激光炮放在第一个点可行,输出YES,否则,以第一个点和第二个点为基础,画出第一个点和第二个点的米字型八个方向上的直线所产生的12个交点,这12个交点为如果激光炮能够消灭所有敌人,那么激光炮只能在这十二个点中的其中一个,然后再遍历
个敌人,对每个敌人,判断该敌人是否能够被这12个点中的一个或多个点攻击到,若能的将这个点的消灭敌人数量+1,最后再判断这十二个点是否存在一个点能消灭n个敌人,即消灭敌人数为n,若存在,则输出YES,反之则输出NO。
十二红色点的坐标可一一标出,注意某些点可能为分数,若点为分数则不记录
假设第一次遍历找到的两个为和
,则这十二个点分别为:
代码:
/*
author:wuzx
*/
#include<bits/stdc++.h>
#define ll long long
#define int long long
#define endl "\n"
#define P pair<int,int>
#define f first
#define s second
using namespace std;
typedef unsigned long long ull;
const int maxn=200010;
const int inf=0x3f3f3f3f;
const int mod=998244353;
int t;
int n,m,k;
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>t;
while(t--)
{
cin>>n;
vector<P> a(n);
for(int i=0;i<n;i++)
cin>>a[i].f>>a[i].s;
bool flag=true;
int aa=a[0].f,bb=a[0].s,x,y;
for(int i=1;i<n;i++)
{
if(a[i].s==a[0].s||a[i].f==a[0].f||abs(a[i].s-a[0].s)==abs(a[i].f-a[0].f))
continue;
else
{
flag=false;
x=a[i].f;
y=a[i].s;
}
}
if(flag)
{
cout<<"YES"<<endl;
continue;
}
else
{
vector<P> point;
point.emplace_back(aa-y+bb,y);
point.emplace_back(x+y-bb,bb);
point.emplace_back(aa,y+x-aa);
point.emplace_back(x,bb-x+aa);
point.emplace_back(x,x-aa+bb);
point.emplace_back(aa,aa-x+y);
point.emplace_back(aa,y);
point.emplace_back(x,bb);
point.emplace_back(aa+y-bb,y);
point.emplace_back(x-y+bb,bb);
if((x-y+bb+aa)%2==0&&(aa-x+y+bb)%2==0)
point.emplace_back((x-y+bb+aa)/2,(aa-x+y+bb)/2);
if((x+aa+y-bb)%2==0&&(x-aa+bb+y)%2==0)
point.emplace_back((x+aa+y-bb)/2,(x-aa+bb+y)/2);
vector<int> vis(point.size(),0);
for(int i=0;i<n;i++)
{
for(int j=0;j<point.size();j++)
{
int xx=point[j].f,yy=point[j].s;
if(a[i].s==yy||a[i].f==xx||abs(a[i].s-yy)==abs(a[i].f-xx))
{
vis[j]++;
continue;
}
}
}
bool ans=false;
for(int x1:vis)
{
if(x1==n)
ans=true;
}
if(ans)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
}
return 0;
}